ios - 如何在 CAShapeLayer 上仅填充形状的一部分
问题描述
我正在使用 UIBezierPath 创建以下形状,然后使用 CAShapeLayer 绘制它,如下所示。
然后我可以将 CAShapeLayer fillColor 属性从shapeLayer.fillColor = UIColor.clear.cgColor
to更改为shapeLayer.fillColor = UIColor.blue.cgColor
并获得以下形状。
这是代码:
import UIKit
class ViewController: UIViewController {
var line = [CGPoint]()
let bezierPath: UIBezierPath = UIBezierPath()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
let point1 = CGPoint(x: 100, y: 100)
let point2 = CGPoint(x: 400, y: 100)
line.append(point1)
line.append(point2)
addCircle(toRight: false)
addLine()
addCircle(toRight: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = bezierPath.cgPath
shapeLayer.strokeColor = UIColor.blue.cgColor
shapeLayer.fillColor = UIColor.clear.cgColor
self.view.layer.addSublayer(shapeLayer)
}
func addLine() -> Void {
bezierPath.move(to: line.first!)
bezierPath.addLine(to: line.last!)
}
func addCircle(toRight: Bool) -> Void {
let angle = CGFloat( Double.pi / 180 )
let r = CGFloat(20.0)
let x0 = toRight ? line.first!.x : line.last!.x
let y0 = toRight ? line.first!.y : line.last!.y
let x1 = toRight ? line.last!.x : line.first!.x
let y1 = toRight ? line.last!.y : line.first!.y
let x = x1 - x0
let y = y1 - y0
let h = (x*x + y*y).squareRoot()
let x2 = x0 + (x * (h + r) / h)
let y2 = y0 + (y * (h + r) / h)
// Add the arc, starting at that same point
let point2 = CGPoint(x: x2, y: y2)
let pointZeroDeg = CGPoint(x: x2 + r, y: y2)
self.bezierPath.move(to: pointZeroDeg)
self.bezierPath.addArc(withCenter: point2, radius: r,
startAngle: 0*angle, endAngle: 360*angle,
clockwise: true)
self.bezierPath.close()
}
}
但我真正想要的是跟随形状(左侧圆圈已填充,右侧圆圈未填充)。
所以我的问题是,如何在 CAShapeLayer 上只填充部分形状? 可能吗?有什么诀窍可以做到这一点吗?
PS:我可以通过创建 3 个不同的 UIBezierPaths(用于 leftCircle、line 和 rightCircle)并使用 3 个不同的 CAShapeLayers 绘制它们来实现这一点,如下所示。
// left Circle
shapeLayer1.path = bezierPath1.cgPath
shapeLayer1.fillColor = UIColor.blue.cgColor
// line
shapeLayer2.path = bezierPath2.cgPath
// right Circle
shapeLayer3.path = bezierPath3.cgPath
shapeLayer3.fillColor = UIColor.clear.cgColor
self.view.layer.addSublayer(shapeLayer1)
self.view.layer.addSublayer(shapeLayer2)
self.view.layer.addSublayer(shapeLayer3)
但我更喜欢使用单个 CAShapeLayer 来实现这一点。
解决方案
我认为更好的方法是使用多种形状。
但是,您可以使用evenOdd
形状填充规则来实现单一形状。
只需在方法的右侧圆圈中添加一个额外的圆圈addCircle
:
if toRight {
self.bezierPath.addArc(withCenter: point2, radius: r,
startAngle: 0*angle, endAngle: 2*360*angle,
clockwise: true)
} else {
self.bezierPath.addArc(withCenter: point2, radius: r,
startAngle: 0*angle, endAngle: 360*angle,
clockwise: true)
}
并设置fillRule
为evenOdd
:
shapeLayer.fillColor = UIColor.blue.cgColor
shapeLayer.fillRule = .evenOdd
所以你会发现左边的圆圈会有一个画圈,并且会被evenOdd
规则填充。但是右边的圆圈会有两个画圈,并且是空的。
evenOdd
规则(https://developer.apple.com/documentation/quartzcore/cashapelayerfillrule/1521843-evenodd ):
指定奇偶缠绕规则。计算路径交叉的总数。如果交叉的数量是偶数,则该点在路径之外。如果交叉点的数量是奇数,则该点位于路径内,并且应该填充包含它的区域。
推荐阅读
- apache - 带有文件夹名称和两个变量的漂亮 url
- mysql - 如何在mysql数据库中存储公交路线的方向?
- javascript - 如何在秒表中添加分钟
- java - Spring Thymeleaf 找不到 js/css
- sql - 如何在 Postgres 中自动创建对 CREATE 的评论?
- vue.js - 无法在 vue 3 组合 API 中的组件上使用模板引用
- postman - 即使通过firebase提供文件,邮递员也没有上传文件
- python - 使用 pandas 找不到 Google Colaboratory 文件
- reactjs - 使用 map() 在 react-native 中处理复选框
- numpy - dask.array.from_array(np.random.random) 和 dask.array.random.random 有什么区别