You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS UIView渲染异常:旋转后的自定义遮罩无法正确显示

问题原因

当你给triangleView设置transform旋转变换后,maskLayer的路径是基于视图未旋转的原始bounds创建的,且遮罩层没有同步应用该旋转变换。这导致旋转后的视图内容与遮罩路径错位,出现部分区域未被遮挡的异常。

解决方案

将旋转变换同步应用到maskLayer上,让遮罩路径与旋转后的视图内容匹配,有两种实现方式:

方式一:给遮罩层添加旋转变换

取消对triangleView的transform设置,转而给视图的layer和遮罩层maskLayer分别添加相同的旋转变换:

// 替换原triangleView.transform及maskLayer相关代码
let rotationAngle = CGFloat(0.523)
// 给视图layer添加旋转变换
triangleView.layer.transform = CATransform3DMakeRotation(rotationAngle, 0, 0, 1)

let maskLayer = CAShapeLayer()
maskLayer.path = UIBezierPath(triangleIn: triangleView.bounds).cgPath
// 给遮罩层添加相同的旋转变换
maskLayer.transform = CATransform3DMakeRotation(rotationAngle, 0, 0, 1)
triangleView.layer.mask = maskLayer

方式二:给路径添加旋转变换

在创建遮罩路径时直接应用旋转变换,保持视图的transform设置不变:

// 替换原maskLayer相关代码
let rotationAngle = CGFloat(0.523)
triangleView.transform = triangleView.transform.rotated(by: rotationAngle)

let maskLayer = CAShapeLayer()
let trianglePath = UIBezierPath(triangleIn: triangleView.bounds)
// 给路径添加旋转变换
trianglePath.apply(CGAffineTransform(rotationAngle: rotationAngle))
maskLayer.path = trianglePath.cgPath
triangleView.layer.mask = maskLayer
修改后的完整代码(方式一)
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
        
        let rotationAngle = CGFloat(0.523)
        triangleView.layer.transform = CATransform3DMakeRotation(rotationAngle, 0, 0, 1)

        let maskLayer = CAShapeLayer()
        maskLayer.path = UIBezierPath(triangleIn: triangleView.bounds).cgPath
        maskLayer.transform = CATransform3DMakeRotation(rotationAngle, 0, 0, 1)
        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)
    }
}

内容的提问来源于stack exchange,提问作者Fan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 12:59:56