持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第11天,点击查看活动详情
需求背景
开发中总会遇到花里胡哨的设计师提出可可爱爱的要求,比如这次设计师要求实现一个爱心状头像样式。
需求的爱心样式是非规则带有角度并且只有重合部分是透明的,从实现难度来说好像是有可行性方案的,因此一口答应设计要求。
方案实现
Xfermode图层混合模式
在过去写过Android的Xfermode介绍在Flutter
开发中是同理的。Flutter
绘制也支持同样的逻辑形式因此上述的头像样式采用SRC_IN
即可实现。
但实际情况是头像图片加载是使用Image
组件而Xfermode
适用于在画布绘制中,若采用这种方案实现开发成本其实不小需要Image
组件从中在图片绘制层上做文章,入参一个遮罩图资源将两者合并后最终再绘制到画布上。
综合来看Xfermode
技术方案更适用于Canvas
在画布是进行绘制操作做比较合适,不支持用于widget
之间进行混合效果。
因此该方案暂时不作为优先级最高的实现方式,需要考虑其他更优方案实现。
ClipPath裁剪
ClipPath
可以通过Path
裁剪组件,同类组件还有ClipRect
、ClipOval
、ClipRRect
提供较为基础裁剪形状。由于要实现的样式是非规则样式因此采用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
路径。
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;
}
小结
实现该需求主要是两点:
- 采用
ClipPath
实现组件裁剪功能 - 利用SVG特点可转换出
Path
提供ClipPath
形状。