15、 Flutter Widgets 之 ClipRect,ClipRRect,ClipOval,ClipPath,CustomClipper,裁剪组件

ClipRect


ClipRect组件使用矩形裁剪子组件,通常情况下,ClipRect作用于CustomPaint 、 CustomSingleChildLayout 、 CustomMultiChildLayout 、 Align 、 Center 、 OverflowBox 、 SizedOverflowBox组件,例如ClipRect作用于Align,可以仅显示上半部分(可以通过alignment控制显示的位置),代码如下:

ClipRect(
      child: Align(
        alignment: Alignment.topCenter,
        heightFactor: 0.5,
        child: Container(
          height: 200,
          width: 200,
          child: Image.network('https://img2.baidu.com/it/u=1974206649,3691483036&fm=26&fmt=auto',fit: BoxFit.cover,),
        ),
      ),
    )

15、 Flutter Widgets 之 ClipRect,ClipRRect,ClipOval,ClipPath,CustomClipper,裁剪组件

 

clipper参数定义裁剪规则,下面具体介绍。

clipBehavior参数定义了裁剪的方式,只有子控件超出父控件的范围才有裁剪的说法,各个方式说明如下:

  • none:不裁剪,系统默认值,如果子组件不超出边界,此值没有任何性能消耗。

  • hardEdge:裁剪但不应用抗锯齿,速度比none慢一点,但比其他方式快。

  • antiAlias:裁剪而且抗锯齿,此方式看起来更平滑,比antiAliasWithSaveLayer快,比hardEdge慢,通常用于处理圆形和弧形裁剪。

  • antiAliasWithSaveLayer:裁剪、抗锯齿而且有一个缓冲区,此方式很慢,用到的情况比较少。

ClipRRect 


构造函数字段:

const ClipRRect({
    Key key,
    this.borderRadius = BorderRadius.zero,// 圆角
    this.clipper, // CustomClipper 对象,如果为空,则裁剪区域为 child 指定的大小
    this.clipBehavior = Clip.antiAlias,// 裁剪的方式, 不能为 null 或者 Clip.none
    Widget child,
  })

ClipRRect组件可以对子组件进行圆角裁剪,默认圆角半径为0,注意ClipRRect有2个R,不是上面介绍的ClipRect。

ClipRRect(
      borderRadius: BorderRadius.vertical(top: Radius.circular(20),bottom: Radius.circular(100)),
      child: Container(
        height: 300,
        width: 300,
        child:Image.network('https://img2.baidu.com/it/u=1974206649,3691483036&fm=26&fmt=auto',fit: BoxFit.cover,) ,
      ),
    )

15、 Flutter Widgets 之 ClipRect,ClipRRect,ClipOval,ClipPath,CustomClipper,裁剪组件

 通过一下代码可以调整任何一个交的圆角裁剪:

borderRadius: BorderRadius.only(
          topLeft: Radius.circular(20),
        bottomLeft: Radius.circular(20),
        topRight: Radius.circular(40),
        bottomRight:Radius.circular(80)

      ),

15、 Flutter Widgets 之 ClipRect,ClipRRect,ClipOval,ClipPath,CustomClipper,裁剪组件

 ClipOval


ClipOval裁剪为椭圆形,椭圆形的大小为正切父组件,因此如果父组件为正方形,切出来是圆形,用法如下:

ClipOval(
      child: Container(
        height: 200,
        width: 300,
        child: _image,
      ),
    )

15、 Flutter Widgets 之 ClipRect,ClipRRect,ClipOval,ClipPath,CustomClipper,裁剪组件

 ClipPath


ClipPath组件根据路径进行裁剪,我们自定义裁剪路径也可以使用系统提供的,用法如下:

ClipPath.shape(
      child: Container(
        height: 200,
        width: 200,
        child: _image,
      ), 
      shape: StadiumBorder(),
    )

15、 Flutter Widgets 之 ClipRect,ClipRRect,ClipOval,ClipPath,CustomClipper,裁剪组件

shape参数是ShapeBorder类型,系统已经定义了很多形状,介绍如下:

  • RoundedRectangleBorder:圆角矩形

  • ContinuousRectangleBorder:直线和圆角平滑连续的过渡,和RoundedRectangleBorder相比,圆角效果会小一些。

  • StadiumBorder:类似于足球场的形状,两端半圆。

  • BeveledRectangleBorder:斜角矩形。

CustomClipper


CustomClipper并不是一个组件,而是一个abstract(抽象)类,使用CustomClipper可以绘制出任何我们想要的形状,比如三角形,代码如下:

_buildClipCustom1(){
    return Center(
          child: ClipPath(
            clipper: MyClippper(),
            child: Container(
              height: 300,
              width: 300,
              child: _image,
            ),
          ),
    );
  }

自定义Myclipper代码如下:

class MyClippper extends CustomClipper<Path>{
  Path path =Path();

  @override
  Path getClip(Size size) {
    Path path = Path();
    // 从 60,0 开始
    path.moveTo(60, 0);
    // 二阶贝塞尔曲线画弧
    path.quadraticBezierTo(0, 0, 0, 60);
    // 连接到底部
    path.lineTo(0, size.height / 1.2);
    // 三阶贝塞尔曲线画弧
    path.cubicTo(size.width / 4, size.height, size.width / 4 * 3, size.height / 1.5, size.width, size.height / 1.2);
    // 再连接回去
    path.lineTo(size.width, 60);
    // 再用二阶贝塞尔曲线画弧
    path.quadraticBezierTo(size.width - 60, 60, size.width - 60, 0);
    return path;
  }

  @override
  bool shouldReclip(covariant CustomClipper<Path> oldClipper) {
    return false;
    // TODO: implement shouldReclip
  }
  
}

效果如下:15、 Flutter Widgets 之 ClipRect,ClipRRect,ClipOval,ClipPath,CustomClipper,裁剪组件

 绘制三角形:

class TrianglePath extends CustomClipper<Path>{
  @override
  Path getClip(Size size) {
    var path = Path();
    path.moveTo(size.width/2, 0);
    path.lineTo(0, size.height);
    path.lineTo(size.width, size.height);
    return path;
  }

  @override
  bool shouldReclip(CustomClipper<Path> oldClipper) {
    return true;
  }
}

 15、 Flutter Widgets 之 ClipRect,ClipRRect,ClipOval,ClipPath,CustomClipper,裁剪组件

绘制五角星:

class StarPath extends CustomClipper<Path> {
  StarPath({this.scale = 2.5});

  final double scale;

  double perDegree = 36;

  /// 角度转弧度公式
  double degree2Radian(double degree) {
    return (pi * degree / 180);
  }

  @override
  Path getClip(Size size) {
    var R = min(size.width / 2, size.height / 2);
    var r = R / scale;
    var x = size.width / 2;
    var y = size.height / 2;

    var path = Path();
    path.moveTo(x, y - R);
    path.lineTo(x - sin(degree2Radian(perDegree)) * r,
        y - cos(degree2Radian(perDegree)) * r);
    path.lineTo(x - sin(degree2Radian(perDegree * 2)) * R,
        y - cos(degree2Radian(perDegree * 2)) * R);
    path.lineTo(x - sin(degree2Radian(perDegree * 3)) * r,
        y - cos(degree2Radian(perDegree * 3)) * r);
    path.lineTo(x - sin(degree2Radian(perDegree * 4)) * R,
        y - cos(degree2Radian(perDegree * 4)) * R);
    path.lineTo(x - sin(degree2Radian(perDegree * 5)) * r,
        y - cos(degree2Radian(perDegree * 5)) * r);
    path.lineTo(x - sin(degree2Radian(perDegree * 6)) * R,
        y - cos(degree2Radian(perDegree * 6)) * R);
    path.lineTo(x - sin(degree2Radian(perDegree * 7)) * r,
        y - cos(degree2Radian(perDegree * 7)) * r);
    path.lineTo(x - sin(degree2Radian(perDegree * 8)) * R,
        y - cos(degree2Radian(perDegree * 8)) * R);
    path.lineTo(x - sin(degree2Radian(perDegree * 9)) * r,
        y - cos(degree2Radian(perDegree * 9)) * r);
    path.lineTo(x - sin(degree2Radian(perDegree * 10)) * R,
        y - cos(degree2Radian(perDegree * 10)) * R);
    return path;
  }

  @override
  bool shouldReclip(StarPath oldClipper) {
    return oldClipper.scale != this.scale;
  }
}

15、 Flutter Widgets 之 ClipRect,ClipRRect,ClipOval,ClipPath,CustomClipper,裁剪组件

 下面用动画动态设置scale,代码如下:

class StartClip extends StatefulWidget {
  const StartClip({Key? key}) : super(key: key);

  @override
  _StartClipState createState() => _StartClipState();
}

class _StartClipState extends State<StartClip> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation _animation;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _controller = AnimationController(vsync: this,duration: Duration(seconds: 2))
    ..addStatusListener((status) {
      if(status == AnimationStatus.completed){
        _controller.reset();
      }else if(status == AnimationStatus.dismissed){
        _controller.forward();
      }
    });
    _animation = Tween(begin: 1,end: 3.0).animate(_controller);
    _controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: AnimatedBuilder(
        builder: (context,child){
          return ClipPath(
            clipper: StarPath(scale: _animation.value),
            child: Container(
              height: 150,
              width: 150,
              color: Colors.red,
            ),
          );
        },
        animation: _animation,
      ),
    );
  }
}

15、 Flutter Widgets 之 ClipRect,ClipRRect,ClipOval,ClipPath,CustomClipper,裁剪组件

 

上一篇:Docker 基于Dockerfile创建镜像实践


下一篇:Dockerfile保留字指令