Search code examples
flutteruser-interfacedecoration

How to achieve this UI in Flutter?


enter image description here

I need a rearrangeable triangle as an indicator above the container widget, which also gets the gradient of the container applied.

Right now the red triangle is a custom paint, but I am open to do it in another way. The location of it must be customisable. Everything is good till the gradient comes into play, because I cannot append it to the triangle as well.

So what I would need is a widget which combines the two elements (triangle and container) and lets me define a decoration for it just like for a normal container.

enter image description here Any ideas on how to solve something like that?


Solution

  • Use ClipPath() and for custom shape button I suggest to check that

              ClipPath(
                clipper: CustomButton(),
                child: Container(
                  height: 150,
                  width: 600,
                  decoration: const BoxDecoration(
                      gradient: LinearGradient(
                        colors: [
                          Colors.blue,
                          Colors.deepPurple,
                        ],
                        begin: FractionalOffset(0.0, 0.0),
                        end: FractionalOffset(1.0, 1.0),
                        stops: [0.0, 1.0],
                        tileMode: TileMode.clamp,
                      )
                  ),
                ),
              )
    ...
    class ArrowClipper extends CustomClipper<Path> {
      @override
      Path getClip(Size size) {
    final Path path = Path();
        path.moveTo(size.width*0.2788164,0);
        path.lineTo(size.width*0.2797843,0);
        path.cubicTo(size.width*0.2866704,size.height*0.03013193,size.width*0.2916482,size.height*0.06854881,size.width*0.2975996,size.height*0.1026649);
        path.cubicTo(size.width*0.2998894,size.height*0.1151187,size.width*0.3014602,size.height*0.1321108,size.width*0.3046405,size.height*0.1401319);
        path.cubicTo(size.width*0.3129093,size.height*0.1453562,size.width*0.3213164,size.height*0.1418997,size.width*0.3296460,size.height*0.1425330);
        path.cubicTo(size.width*0.5416704,size.height*0.1424011,size.width*0.7536947,size.height*0.1425594,size.width*0.9657190,size.height*0.1424538);
        path.cubicTo(size.width*0.9740321,size.height*0.1419789,size.width*0.9831139,size.height*0.1488391,size.width*0.9893418,size.height*0.1775462);
        path.cubicTo(size.width*0.9951493,size.height*0.1999208,size.width*0.9987611,size.height*0.2330343,size.width,size.height*0.2678628);
        path.lineTo(size.width,size.height*0.8773879);
        path.cubicTo(size.width*0.9988827,size.height*0.9051979,size.width*0.9963827,size.height*0.9319525,size.width*0.9923894,size.height*0.9530871);
        path.cubicTo(size.width*0.9878374,size.height*0.9787863,size.width*0.9811007,size.height*0.9936675,size.width*0.9742865,size.height);
        path.lineTo(size.width*0.02569690,size.height);
        path.cubicTo(size.width*0.01769358,size.height*0.9929551,size.width*0.01011615,size.height*0.9720317,size.width*0.005470133,size.height*0.9397361);
        path.cubicTo(size.width*0.002323009,size.height*0.9201319,size.width*0.001111726,size.height*0.8954881,0,size.height*0.8718734);
        path.lineTo(0,size.height*0.2732454);
        path.cubicTo(size.width*0.001299779,size.height*0.2307124,size.width*0.005945796,size.height*0.1888918,size.width*0.01383850,size.height*0.1663852);
        path.cubicTo(size.width*0.02036504,size.height*0.1438259,size.width*0.02874447,size.height*0.1420053,size.width*0.03649336,size.height*0.1422427);
        path.cubicTo(size.width*0.1065653,size.height*0.1429024,size.width*0.1766427,size.height*0.1420317,size.width*0.2467201,size.height*0.1427441);
        path.cubicTo(size.width*0.2495077,size.height*0.1397361,size.width*0.2535177,size.height*0.1469921,size.width*0.2556305,size.height*0.1350923);
        path.cubicTo(size.width*0.2632688,size.height*0.08978892,size.width*0.2701604,size.height*0.04110818,size.width*0.2788164,0);
        path.close();
    
        return path;
      }
    
      @override
      bool shouldReclip(CustomClipper<Path> oldClipper) => true;
    }