1、iOS17方案
iOS17上可以同时对shape调用fill和stroke:
Circle()
.stroke(.red, lineWidth: 20)
.fill(.orange)
.frame(width: 150, height: 150)
效果也如我们所预料的:
而且stroke可以调用任意次:
Circle()
.stroke(.blue, lineWidth: 45)
.stroke(.green, lineWidth: 35)
.stroke(.yellow, lineWidth: 25)
.stroke(.orange, lineWidth: 15)
.stroke(.red, lineWidth: 5)
.frame(width: 150, height: 150)
最终的效果是在Circle外边加了好几圈border。
2、iOS16方案
iOS16及之前虽然也有stroke、fill方法,但是将它们像iOS17那样写在一起是无效的。一个替代方案是使用strokeBorder或stroke给shape增加一个border来实现stroke的效果,然后用shape的fill版本来作为background,将它们叠在一起就能实现我们需要的效果:
Circle()
.strokeBorder(.red, lineWidth: 20)
.background(Circle().fill(.orange))
.frame(width: 150, height: 150)
.border(.green)
值得注意的一点是strokeBorder的调用对象是InsettableShapes,从视觉上看,border是加在shape的frame内的,而shape本身就好像被加了insets,变得越来越小了。而stroke版本,border中心恰好在frame边界上:
Circle()
.stroke(.red, lineWidth: 20)
.background(Circle().fill(.orange))
.frame(width: 150, height: 150)
.border(.green)
基于上面的方案,我们也很容易想到使用Zstack或者overlay来叠出相同的视觉效果:
ZStack {
Circle()
.fill(.orange)
Circle()
.strokeBorder(.red, lineWidth: 20)
}
.frame(width: 150, height: 150)
3、参考资料
How to fill and stroke shapes at the same time