提问人:Fan 提问时间:8/14/2023 最后编辑:Fan 更新时间:8/16/2023 访问量:53
iOS UIView 渲染问题:渲染后旋转蒙版显示不正确
iOS UIView Rendering Issue: Incorrect Display of Rotated Mask After Rendering
问:
我尝试在 CustomView 中渲染 imageView,发现 triangleView 的蒙版在旋转后没有正确渲染,并且没有覆盖其中的一部分。
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)
}
}
我希望自定义路径的掩码正常呈现
答:
0赞
DonMag
8/16/2023
#1
当视图的框架更改大小时,图层和图层蒙版不会自动调整大小。
如果我们在三角形视图的“下方”添加一个轮廓分明的半透明黄色视图,并在旋转三角形视图时更新其框架,我们可以看到(某种程度上)发生了什么......
一、不带旋转变换:
然后,在旋转变换后:
非常古怪的结果,但显然是由于内部工作方式:UIView.layer.render(in: context)
此方法直接从图层树进行渲染,忽略添加到渲染树的任何动画。在图层的坐标空间中渲染。
根据您的最终目标和需求,一种选择是为您的三角形视图使用子类,例如(使用 UIBezierPath 扩展):UIView
triangleIn rect:
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)
}
}
结果:
上一个:在 SWIFT 中向下投射
下一个:在 Web 视图中隐藏弹出窗口
评论