UIBezierPath: roundedRect: byRoundingCorners: cornerRadii: acting weird

I am trying to make two button corners. If I choose .TopLeft and .BottomLeft like this:

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 

how the code works beautifully.

If I chose .TopRight and. BottomRight like this:

 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 

than I do not see round corners. What's going on here?

I already tried adding maskAdsLayer as a subquery, and it does not work.

+4
source share
2 answers

If you do this in viewDidLoad , the auto-layout constraints may not have been applied by this point, and therefore, the frame of your button may not have an end value, and therefore disableAdsButton.bounds is probably not what you expect in this moment. Thus, corners that are rounded to the right may not be visible. You can confirm this by registering the bounds button at the point at which this code runs, and then review it again after the views are displayed.

You can solve this problem by deferring it to viewDidAppear or, better, viewDidLayoutSubviews .

+3
source

After finding this answer (thanks for the kickstart) and experimenting with the missing details, here is my final understanding:

  • a layer needs to be created only once
  • it should be updated when the view rectangle changes
  • best place to grab that is in layoutSubviews ()

We can use the ability to have our own layer shape class for the UIView to encapsulate this a bit. So first, we define our own layer class using the CAShapeLayer mask:

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

Then we can use it in a 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) } } 

There is more work to make the angles customizable, but what a spirit.

0
source

All Articles