Flutter: inverted ClipOval

后端 未结 1 1451
北恋
北恋 2020-12-09 05:59

I am new to Flutter and I am trying to write a library to allow users to pan/zoom their profile picture.

In order to make it visual, I would like to stack their pict

1条回答
  •  有刺的猬
    2020-12-09 06:03

    There's a couple other ways you could do this - you could simply draw an overlay in a CustomCanvas using a path that has a circle & rectangle, as all you really need is a rectangular semi-transparent rectangle with a hole in it. But you can also use a CustomClipper which gives you more flexibility in the future without having to draw stuff manually.

    void main() {
      int i = 0;
      runApp(new MaterialApp(
          home: new SafeArea(
            child: new Stack(
              children: [
                new GestureDetector(
                  onTap: () {
                    print("Tapped! ${i++}");
                  },
                  child: new Container(
                    color: Colors.white,
                    child: new Center(
                      child: new Container(
                        width: 400.0,
                        height: 300.0,
                        color: Colors.red.shade100,
                      ),
                    ),
                  ),
                ),
                new IgnorePointer(
                  child: new ClipPath(
                    clipper: new InvertedCircleClipper(),
                    child: new Container(
                      color: new Color.fromRGBO(0, 0, 0, 0.5),
                    ),
                  ),
                )
              ],
            ),
          ),
        ));
    }
    
    class InvertedCircleClipper extends CustomClipper {
      @override
      Path getClip(Size size) {
        return new Path()
          ..addOval(new Rect.fromCircle(
              center: new Offset(size.width / 2, size.height / 2),
              radius: size.width * 0.45))
          ..addRect(new Rect.fromLTWH(0.0, 0.0, size.width, size.height))
          ..fillType = PathFillType.evenOdd;
      }
    
      @override
      bool shouldReclip(CustomClipper oldClipper) => false;
    }
    

    IgnorePointer is needed, or events won't be propagated through the semi-transparent part (assuming you need touch events).

    How this works is that the Path used by clipPath is a circle in the middle (you need to adjust the size manually) with a rectangle taking up the entire size. fillType = PathFillType.evenOdd is important because it tells the path's fill should be between the circle and the rectangle.

    If you wanted to use a customPainter instead, the path would be the same and you'd just draw it instead.

    This all results in this:

    0 讨论(0)
提交回复
热议问题