Swift: 是否有更快、更灵敏的方法来为 UIView 实现不同的角半径?

Swift: Is there a faster, more responsive way to implement different corner radii for a UIView?

目前,我在我的 bubbleView 上实现了多个角半径,这是一个 UIView,方法是:

// First create the bubble view
bubbleView = UIView()
bubbleView.layer.cornerRadius = 4 // set the corner radius of the "smaller" corner style
bubbleView.layer.cornerCurve = .continuous
bubbleView.clipsToBounds = true
bubbleView.backgroundColor = UIColor.systemBlue

// ...

// Update the "mask" of the bubble view to give another type of rounded corners
let maskPath = UIBezierPath(roundedRect:bubbleView.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: 17.0, height: 0.0))
let maskLayer = CAShapeLayer()
maskLayer.path = maskPath.cgPath
bubbleView.layer.mask = maskLayer // updates the mask

我的问题是我在 func layoutSubviews() 函数中设置 bubbleView 的掩码 self.bubbleView.layer.mask = maskLayer,这会导致明显的延迟,例如,当设备从纵向到横向模式。

是否有更快、更有效的方法来为 UIView 实现不同的角半径,其响应速度比简单地更新 layoutSubviews() 中的掩码更快?

您可以尝试使用具有较大半径角的子视图...

  • 自定义视图
  • 背景清晰
  • 所有 4 个角都设置为 4 的半径
  • 具有所需背景颜色的子视图
  • 在子视图的所需角上设置 17 的半径

下面是一些示例代码:

class MyCustomView: UIView {

    // self's background will be .clear
    //  so we use a custom property to set the
    //  background of the subView
    public var viewColor: UIColor = .clear {
        didSet {
            subView.backgroundColor = viewColor
        }
    }
    
    // corners to use larger radius
    public var corners: CACornerMask = [] {
        didSet {
            subView.layer.maskedCorners = corners
        }
    }
    
    public var smallRadius: CGFloat = 0 {
        didSet {
            layer.cornerRadius = smallRadius
        }
    }

    public var bigRadius: CGFloat = 0 {
        didSet {
            subView.layer.cornerRadius = bigRadius
        }
    }
    
    private let subView = UIView()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    
    func commonInit() -> Void {
        
        addSubview(subView)
        subView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            subView.topAnchor.constraint(equalTo: topAnchor),
            subView.leadingAnchor.constraint(equalTo: leadingAnchor),
            subView.trailingAnchor.constraint(equalTo: trailingAnchor),
            subView.bottomAnchor.constraint(equalTo: bottomAnchor),
        ])

        // round all 4 corners of self's layer with the small radius
        layer.masksToBounds = true
        layer.cornerRadius = smallRadius
        layer.cornerCurve = .continuous

        // subview only specified corners with bigger radius
        subView.layer.masksToBounds = true
        subView.layer.cornerRadius = bigRadius
        subView.layer.cornerCurve = .continuous
        subView.layer.maskedCorners = corners

    }
    
}

和一个用于演示的测试视图控制器:

class TestViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let v = MyCustomView()

        v.viewColor = .systemBlue
        v.smallRadius = 4
        v.bigRadius = 17
        
        // set top-left, top-right, bottom-left to use larger radius
        v.corners = [.layerMinXMinYCorner, .layerMaxXMinYCorner, .layerMinXMaxYCorner]
        
        v.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(v)
        let g = view.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            v.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 60.0),
            v.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -60.0),
            v.heightAnchor.constraint(equalToConstant: 120.0),
            v.centerYAnchor.constraint(equalTo: g.centerYAnchor),
        ])
    }
    
}