Flutter自定义Painter和Clipper实现Container的不规则背景

最近在做需求的时候设计师做了一个背景不规则的icon,如下图:


企业微信20240708-174145.png

由于之后背景的渐变,描边的颜色和内部的字体可能都会变化,所以不采用直接切图的方式来做。
如果直接使用flutter的decoration来做的话没有办法直接实现,所以就决定用自定义painter和clipper的方法实现了

第一步,很简单的画Container的渐变背景,用decoration直接实现

Container(
    width: 200,
    height: 100,
    decoration: const BoxDecoration(
    gradient:  LinearGradient(
         begin: Alignment.centerLeft,
         end: Alignment.centerRight,
         colors: [
             Color(0xFFFFD5D5),
             Color(0xFFFFECE6),
         ],
     ),
  ),
)

很简单,如图所示:


11.jpg

第二步,通过ClipPath来裁剪背景,因为左侧是一个半圆,所以半圆的半径就是Container高度的一半

class MyClipper extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    Path path = Path();
    path.moveTo(0, 0);
    final center = Offset(size.height / 2, size.height / 2);
    final radius = math.min(size.width, size.height) / 2;
    path.arcTo(
      Rect.fromCircle(center: center, radius: radius),
      math.pi / 2, //注意要旋转90度才可以是左侧的半圆
      math.pi,
      true,
    );
    path.close();
    path.moveTo(size.height / 2, size.height);
    path.lineTo(size.width - 15, size.height);
    path.lineTo(size.width, 0);
    path.lineTo(size.height / 2, 0);

    return path;
  }

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

背景完成后如图:


11.png

这里需要注意一下,这里如果直接使用decoration的border属性,border也会被Cliper裁减掉,如下图:


11.png

所以内部采用了自定义CustomPaint的Painter的方式来实现子widget和border,代码如下:

class MyPainter extends CustomPainter {
  final myPaint = Paint()
    ..color = Colors.black
    ..isAntiAlias = true
    ..strokeWidth = 5
    ..strokeCap = StrokeCap.round
    ..style = PaintingStyle.stroke;

  @override
  void paint(Canvas canvas, Size size) {
    Path path = Path();
    path.moveTo(0, 0);
    final center = Offset(size.height / 2, size.height / 2);
    final radius = math.min(size.width, size.height) / 2;
    path.arcTo(
      Rect.fromCircle(center: center, radius: radius),
      math.pi / 2,
      math.pi,
      true,
    );
    path.moveTo(size.height / 2, size.height);
    path.lineTo(size.width - 15, size.height);
    path.lineTo(size.width, 0);
    path.lineTo(size.height / 2, 0);
    canvas.drawPath(path, myPaint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return true;
  }
}

几乎和背景的Cliper的path一样,主要是在画完圆弧之后path不要close,要继续画直线。
效果如下图:


11.jpg

这样就实现了不规则图形和描边的绘制~~

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容