UIBezierPath: roundedRect: byRoundingCorners: angleRadii: ведет себя странно

Я пытаюсь сделать 2 угла кнопки круглыми. Если я выберу .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 в качестве подпредставления, и это не сработало.


person potato    schedule 10.08.2015    source источник


Ответы (2)


Если вы делаете это в viewDidLoad, возможно, к этому моменту ограничения автоматического макета не были применены, и, таким образом, рамка вашей кнопки может не иметь своего окончательного значения, и, таким образом, disableAdsButton.bounds, вероятно, не то, что вы ожидаете. точка. Таким образом, углы, которые скругляются вправо, могут быть не видны. Вы можете подтвердить это, зарегистрировав bounds кнопки в момент запуска этого кода, а затем просмотрев его снова после того, как представления были выложены.

Вы можете решить эту проблему, отложив ее до viewDidAppear или, лучше, до viewDidLayoutSubviews.

person Rob    schedule 10.08.2015

Найдя этот ответ (спасибо за кикстарт) и поэкспериментировав с недостающими деталями, вот мое окончательное понимание:

  • слой нужно создать только один раз
  • он должен обновляться при изменении прямоугольника вида
  • лучшее место для захвата — layoutSubviews()

Мы можем использовать возможность иметь собственный класс формы слоя для UIView, чтобы немного инкапсулировать это. Итак, сначала мы определяем наш собственный класс слоя с маской CAShapeLayer:

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

Есть еще работа, чтобы сделать углы настраиваемыми, но это дух.

person user1427799    schedule 18.11.2016