UIBezierPath: roundedRect: byRoundingCorners: cornerRadii: 行为很奇怪

UIBezierPath: roundedRect: byRoundingCorners: cornerRadii: acts weird

我正在尝试使按钮的两个角变圆。如果我 select .TopLeft 和 .BottomLeft 是这样的:

let bezierDisableAdsPath = UIBezierPath(roundedRect: disableAdsButton.bounds, byRoundingCorners: [UIRectCorner.TopLeft , UIRectCorner.BottomLeft] , cornerRadii: CGSizeMake(4.0, 4.0))

        let maskAdsLayer = CAShapeLayer()
        maskAdsLayer.frame = disableAdsButton.bounds
        maskAdsLayer.path = bezierDisableAdsPath.CGPath
        disableAdsButton.layer.mask = maskAdsLayer

比代码更漂亮。

如果我选择 .TopRight 和 .右下角像这样:

let bezierDisableAdsPath = UIBezierPath(roundedRect: disableAdsButton.bounds, byRoundingCorners: [UIRectCorner.TopRight , UIRectCorner.BottomRight] , cornerRadii: CGSizeMake(4.0, 4.0))

        let maskAdsLayer = CAShapeLayer()
        maskAdsLayer.frame = disableAdsButton.bounds
        maskAdsLayer.path = bezierDisableAdsPath.CGPath
        disableAdsButton.layer.mask = maskAdsLayer

比我看到的没有圆角。这是怎么回事?

我已经尝试将 maskAdsLayer 添加为子视图,但它不起作用。

如果您在 viewDidLoad 中执行此操作,此时可能尚未应用自动布局约束,因此您的按钮框架可能未处于最终值,因此 disableAdsButton.bounds 可能不是您当时期望的那样。因此,向右圆化的角可能不可见。您可以通过在此代码运行时记录按钮的 bounds 来确认这一点,然后在布局视图后再次查看它。

您可以通过推迟到 viewDidAppear 或更好的 viewDidLayoutSubviews.

来解决此问题

找到这个答案(感谢 kickstart),并尝试了缺失的细节,这是我的最终理解:

  • 图层只需要创建一次
  • 它必须在视图的矩形改变时更新
  • 在 layoutSubviews() 中捕获的最佳位置

我们可以使用为 UIView 提供自定义图层形状 class 的功能来稍微封装一下。所以首先,我们用 CAShapeLayer 掩码定义我们自己的层 class:

class RoundedShapeLayer: CAShapeLayer {
  override init() {
    super.init()
    self.mask = CAShapeLayer()
  }    
  override init(layer: Any) {
    super.init(layer: layer)
    self.mask = CAShapeLayer()
  }    
  required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    self.mask = CAShapeLayer()
  }

  func update(for bounds: CGRect) {
    (mask as! CAShapeLayer).path =
        UIBezierPath(roundedRect: bounds,
                     byRoundingCorners: [UIRectCorner.topRight, UIRectCorner.topLeft],
                     cornerRadii: CGSize(width: 10, height: 10)).cgPath

  }
}

然后我们可以在 UIView 中使用它:

@IBDesignable class RoundedCornerView: UIView {    
  override class var layerClass: AnyClass {
    get {
        return RoundedShapeLayer.self
    }
  }

  override init(frame: CGRect) {
    super.init(frame: frame)
  }

  required init?(coder: NSCoder) {
    super.init(coder: coder)
  }

  override func layoutSubviews() {
    super.layoutSubviews()
    (layer as! RoundedShapeLayer).update(for: bounds)
  }
}

要使边角可自定义还有很多工作要做,但这就是精神。