我尝试在CustomView中渲染imageView,发现旋转后triangleView的mask没有正确渲染,有一部分没有被覆盖。
import UIKit
extension UIBezierPath {
convenience init(triangleIn rect: CGRect) {
self.init()
let startX = rect.midX
let startY = rect.minY
let endY = rect.maxY
self.move(to: CGPoint(x: startX, y: startY))
self.addLine(to: CGPoint(x: rect.maxX, y: endY))
self.addLine(to: CGPoint(x: rect.minX, y: endY))
self.close()
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
let w: CGFloat = view.frame.width
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: w, height: w))
imageView.image = UIImage(named: "IMG_2778")
view.addSubview(imageView)
let triangleView = UIView(frame: CGRect(x: w/2, y: w/2, width: 100, height: 100))
triangleView.backgroundColor = .systemBlue
triangleView.transform = triangleView.transform.rotated(by: 0.523)
let maskLayer = CAShapeLayer()
maskLayer.path = UIBezierPath(triangleIn: triangleView.bounds).cgPath
triangleView.layer.mask = maskLayer
imageView.addSubview(triangleView)
let customView = CustomView(frame: CGRect(x: 0, y: w + 10, width: w, height: w))
customView.renderView = imageView
view.addSubview(customView)
}
}
class CustomView: UIView {
var renderView: UIView!
override init(frame: CGRect) {
super.init(frame: frame)
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func draw(_ rect: CGRect) {
guard let context = UIGraphicsGetCurrentContext() else { return }
guard let renderView = renderView else { return }
renderView.layer.render(in: context)
}
}
我希望自定义路径的遮罩能够正常渲染
当视图的框架更改大小时,图层和图层蒙版不会自动调整大小。
如果我们在三角形视图“下方”添加一个轮廓清晰的半透明黄色视图,并在旋转三角形视图时更新其框架,我们可以看到(某种程度上)发生了什么......
首先,没有旋转变换:
然后,旋转变换后:
非常奇怪的结果,但显然是由于
UIView.layer.render(in: context)
内部的工作方式造成的:
此方法直接从图层树渲染,忽略添加到渲染树的任何动画。在图层的坐标空间中渲染。
根据您的最终目标和需求,一种选择是为三角形视图使用
UIView
子类,如下所示(使用您的 triangleIn rect:
UIBezierPath 扩展):
class MyTriangleView: UIView {
override class var layerClass: AnyClass { CAShapeLayer.self }
var shapeLayer: CAShapeLayer { layer as! CAShapeLayer }
override func layoutSubviews() {
super.layoutSubviews()
shapeLayer.path = UIBezierPath(triangleIn: bounds).cgPath
}
}
那么您的
CustomView
不会发生任何变化,而您的原始 ViewController
只会发生微小的变化:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
let w: CGFloat = view.frame.width
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: w, height: w))
imageView.image = UIImage(named: "IMG_2778")
view.addSubview(imageView)
// use custom MyTriangleView
let triangleView = MyTriangleView(frame: CGRect(x: w/2, y: w/2, width: 100, height: 100))
triangleView.shapeLayer.fillColor = UIColor.systemBlue.cgColor
triangleView.transform = triangleView.transform.rotated(by: 0.523)
imageView.addSubview(triangleView)
let customView = CustomView(frame: CGRect(x: 0, y: w + 10, width: w, height: w))
customView.renderView = imageView
view.addSubview(customView)
}
}
结果: