flutter 使用ClipPath实现中间透明 四周半透明,可倒圆角

ClipPath可以根据给定的Path来裁剪widget,它的定义如下:

/// Creates a path clip.
///
/// If [clipper] is null, the clip will be a rectangle that matches the layout
/// size and location of the child. However, rather than use this default,
/// consider using a [ClipRect], which can achieve the same effect more
/// efficiently.
///
/// The [clipBehavior] argument must not be null or [Clip.none].
const ClipPath({
   Key? key,
   this.clipper,
   this.clipBehavior = Clip.antiAlias,
   Widget? child,
})

ClipPath实现中间透明四周半透明步骤

第一步:定义自定义裁剪 - 上半部分

class _TopBackClipper extends CustomClipper<Path> {
  final double _clipWidth;
  final double _borderRadius;
  _TopBackClipper({double clipWidth, double borderRadius}) : _clipWidth = clipWidth, _borderRadius = borderRadius;

  @override
  Path getClip(Size size) {
    var path = Path();
    path.moveTo(0, 0);
    path.lineTo(0, size.height / 2 + 0.1);
    path.lineTo(size.width / 2 - _clipWidth / 2, size.height / 2 + 0.1);
    path.lineTo(size.width / 2 - _clipWidth / 2,
        size.height / 2 - _clipWidth / 2 + _borderRadius);
    //左上角
    path.arcToPoint(Offset(size.width / 2 - _clipWidth / 2 + _borderRadius, size.height / 2 - _clipWidth / 2),
        radius: Radius.circular(_borderRadius));
    path.lineTo(size.width / 2 + _clipWidth / 2 - _borderRadius,
        size.height / 2 - _clipWidth / 2);
    //右上角
    path.arcToPoint(Offset(size.width / 2 + _clipWidth / 2, size.height / 2 - _clipWidth / 2 + _borderRadius),
        radius: Radius.circular(_borderRadius));
    path.lineTo(size.width / 2 + _clipWidth / 2, size.height / 2 + 0.1);
    path.lineTo(size.width, size.height / 2 + 0.1);
    path.lineTo(size.width, 0);
    path.close();
    return path;
  }

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

第二步:定义自定义裁剪 - 下半部分


class _BottomBackClipper extends CustomClipper<Path> {
  final double _clipWidth;
  final double _borderRadius;
  _BottomBackClipper({double clipWidth, double borderRadius}) : _clipWidth = clipWidth, _borderRadius = borderRadius;

  @override
  Path getClip(Size size) {
    var path = Path();

    path.moveTo(0, size.height / 2);
    path.lineTo(size.width / 2 - _clipWidth / 2, size.height / 2);
    path.lineTo(size.width / 2 - _clipWidth / 2,
        size.height / 2 + _clipWidth / 2 - _borderRadius);
    //左下角
    path.arcToPoint(Offset(size.width / 2 - _clipWidth / 2 + _borderRadius, size.height / 2 + _clipWidth / 2 ),
        radius: Radius.circular(_borderRadius), clockwise: false);
    path.lineTo(size.width / 2 + _clipWidth / 2 - _borderRadius,
        size.height / 2 + _clipWidth / 2);
    //右下角
    path.arcToPoint(Offset(size.width / 2 + _clipWidth / 2, size.height / 2 + _clipWidth / 2 - _borderRadius),
        radius: Radius.circular(_borderRadius), clockwise: false);
    path.lineTo(size.width / 2 + _clipWidth / 2, size.height / 2);
    path.lineTo(size.width, size.height/2);
    path.lineTo(size.width, size.height);
    path.lineTo(0, size.height);
    path.close();
    return path;
  }

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

第三步 封装成Widget


class ClipCenter extends StatefulWidget {
  final double boundWidth;//中心裁剪宽度
  final double borderRadius;
  final Color backgroundColor;
  const ClipCenter({Key key, this.boundWidth = 100, this.borderRadius = 8, this.backgroundColor = Colors.lightBlueAccent}) : super(key: key);

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

class _ClipCenterState extends State<ClipCenter> {
  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        Positioned(
          top: 0,
          bottom: 0,
          left: 0,
          right: 0,
          child: ClipPath(
            clipper: _TopBackClipper(clipWidth: widget.boundWidth, borderRadius: widget.borderRadius),
            child: Container(
              color: widget.backgroundColor,
            ),
          ),
        ),
        Positioned(
          top: 0,
          bottom: 0,
          left: 0,
          right: 0,
          child: ClipPath(
            clipper: _BottomBackClipper(clipWidth: widget.boundWidth, borderRadius: widget.borderRadius),
            child: Container(
              color: widget.backgroundColor,
            ),
          ),
        ),
      ],
    );
  }
}

第四部 使用

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值