【Flutter】不规则头像样式开发实现

1,321 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第11天,点击查看活动详情

需求背景

开发中总会遇到花里胡哨的设计师提出可可爱爱的要求,比如这次设计师要求实现一个爱心状头像样式。

image.pngimage.png

需求的爱心样式是非规则带有角度并且只有重合部分是透明的,从实现难度来说好像是有可行性方案的,因此一口答应设计要求。

方案实现

Xfermode图层混合模式

在过去写过Android的Xfermode介绍Flutter开发中是同理的。Flutter绘制也支持同样的逻辑形式因此上述的头像样式采用SRC_IN即可实现。

image.png 但实际情况是头像图片加载是使用Image组件而Xfermode适用于在画布绘制中,若采用这种方案实现开发成本其实不小需要Image组件从中在图片绘制层上做文章,入参一个遮罩图资源将两者合并后最终再绘制到画布上。

综合来看Xfermode技术方案更适用于Canvas在画布是进行绘制操作做比较合适,不支持用于widget之间进行混合效果。 因此该方案暂时不作为优先级最高的实现方式,需要考虑其他更优方案实现。

ClipPath裁剪

ClipPath视频介绍

image.png

ClipPath可以通过Path裁剪组件,同类组件还有ClipRectClipOvalClipRRect提供较为基础裁剪形状。由于要实现的样式是非规则样式因此采用ClipPath来实现。

爱心形状裁剪简单实用

class HeartClipper extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    double width = 150;
    double height = 150;
    Path path = Path();
    path.moveTo(0.5 * width, height * 0.35);
    path.cubicTo(0.2 * width, height * 0.1, -0.25 * width, height * 0.6,
        0.5 * width, height);
    path.moveTo(0.5 * width, height * 0.35);
    path.cubicTo(0.8 * width, height * 0.1, 1.25 * width, height * 0.6,
        0.5 * width, height);
    return path;
  }

  @override
  bool shouldReclip(covariant CustomClipper<Path> oldClipper) => false;
}

ClipPath(
  clipper: HeartClipper(),
  child: Image.network(
    "https://img0.baidu.com/it/u=2521851051,2189866243&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500",
    width: 150,
    height: 150,
    fit: BoxFit.cover,
  ),
)

不规则形状裁剪

不规则样式可以让设计师导出svg格式图片然后通过在线网址将svg图片直接转成Path路径。

image.png svg转画布 wecom-temp-2bb9ab25c35a030518d0dd9de95b59a0.png

class HeartClipper3 extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    Path path = Path();
    path.lineTo(size.width * 0.53, size.height * 0.26);
    path.cubicTo(size.width * 0.34, size.height * 0.17, size.width / 5, size.height / 5, size.width * 0.13, size.height * 0.35);
    path.cubicTo(size.width * 0.05, size.height * 0.51, size.width * 0.24, size.height * 0.75, size.width * 0.68, size.height * 1);
    path.cubicTo(size.width * 1.09, size.height * 0.56, size.width * 1.21, size.height / 4, size.width * 1.03, size.height * 0.13);
    path.cubicTo(size.width * 0.86, size.height * 0.02, size.width * 0.69, size.height * 0.06, size.width * 0.53, size.height * 0.26);
    path.cubicTo(size.width * 0.53, size.height * 0.26, size.width * 0.53, size.height * 0.26, size.width * 0.53, size.height * 0.26);
    return path;
  }

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

image.png

🚀参考代码点击这里查看🚀

小结

实现该需求主要是两点:

  • 采用ClipPath实现组件裁剪功能
  • 利用SVG特点可转换出Path提供ClipPath形状。