Swift:有没有更快、更灵敏的方式来为 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

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

是否有比简单地更新 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),])
    }
    
}