iOS UIView渲染问题:渲染后旋转遮罩显示不正确

问题描述 投票:0回答:1

我尝试在CustomView中渲染imageView,发现旋转后triangleView的mask没有正确渲染,有一部分没有被覆盖。

The exception is shown in the figure

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)
    }
}

我希望自定义路径的遮罩能够正常渲染

ios uiview
1个回答
0
投票

当视图的框架更改大小时,图层和图层蒙版不会自动调整大小。

如果我们在三角形视图“下方”添加一个轮廓清晰的半透明黄色视图,并在旋转三角形视图时更新其框架,我们可以看到(某种程度上)发生了什么......

首先,没有旋转变换:

然后,旋转变换后:

非常奇怪的结果,但显然是由于

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)
    }
}

结果:

© www.soinside.com 2019 - 2024. All rights reserved.