Reputation: 364
I have a XUIView class as below. When I run animation, it's no effect for folding.
Who can explain me ?
class ViewController: UIViewController { // Width constraint of XUIView instance @IBOutlet weak var vwWrapperWidth: NSLayoutConstraint! { didSet{ self.vwWrapperWidth.constant = UIScreen.main.bounds.width } } @IBAction func btnToggleTouchUp(_ sender: UIButton) { if(self.vwWrapperWidth.constant == 55) { // animation effect is OK when expanding self.vwWrapperWidth.constant = UIScreen.main.bounds.width UIView.animate(withDuration: 0.5, animations: { self.view.layoutIfNeeded() }) } else { // animation effect is not OK when folding self.vwWrapperWidth.constant = 55 UIView.animate(withDuration: 0.5, animations: { self.view.layoutIfNeeded() }) } } //..... } @IBDesignable class XUIView: UIView { @IBInspectable var roundTopLeftCorner: Bool = false @IBInspectable var roundBottomLeftCorner: Bool = false @IBInspectable var roundTopRightCorner: Bool = false @IBInspectable var roundBottomRightCorner: Bool = false @IBInspectable var cornerRadius: CGFloat = 0.0 @IBInspectable var borderWidth: CGFloat = 0.0 @IBInspectable var borderColor: UIColor? fileprivate var borderLayer: CAShapeLayer? { didSet{ self.layer.addSublayer(self.borderLayer!) } } func roundCorners(_ corners: UIRectCorner) { if(self.borderLayer == nil) { self.borderLayer = CAShapeLayer() } let bounds = self.bounds let maskPath = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: self.cornerRadius, height: self.cornerRadius)) let maskLayer = CAShapeLayer() maskLayer.frame = bounds maskLayer.path = maskPath.cgPath self.layer.mask = maskLayer self.borderLayer?.frame = bounds self.borderLayer?.path = maskPath.cgPath self.borderLayer?.strokeColor = self.borderColor?.cgColor self.borderLayer?.lineWidth = self.borderWidth self.borderLayer?.fillColor = nil } override func layoutSubviews() { super.layoutSubviews() var roundedCorners: UIRectCorner = [] if(roundTopLeftCorner) { roundedCorners.insert(.topLeft) } if(roundTopRightCorner) { roundedCorners.insert(.topRight) } if(roundBottomLeftCorner) { roundedCorners.insert(.bottomLeft) } if(roundBottomRightCorner) { roundedCorners.insert(.bottomRight) } roundCorners(roundedCorners) } }
source code : http://www.mediafire.com/file/n6svp1mk44fc0uf/TestXUIView.zip/file
Upvotes: 2
Views: 311
Reputation: 741
You are experiencing no animation on the "folding" animation because CALayer
's path
property is not implicitly animatable. It is mentioned here.
Unlike most animatable properties, path (as with all CGPath animatable properties) does not support implicit animation.
To make matters worst, CALayer
's frame
property is not implicitly animatable either. It is mentioned here
Note: The frame property is not directly animatable. Instead you should animate the appropriate combination of the bounds, anchorPoint and position properties to achieve the desired result.
This simply means the following lines won't work, just because it is being called inside a UIView.animate
block.
let maskLayer = CAShapeLayer()
maskLayer.frame = bounds // This line won't animate!
maskLayer.path = maskPath.cgPath // This line won't animate!
self.layer.mask = maskLayer
Since it is not being animated, the mask is applied as soon as the layoutSubviews
method in XUIView
is called. View is actually animating, but you just cannot see it because the mask is being set before the animation completes.
This is also what happens in the expand animation. First the mask expands, then the animation occurs.
To prevent this, you might need to find a way to animate the width constraint and the layer frames & mask paths together.
Upvotes: 2
Reputation: 389
The problem is that you are creating a CAShapeLayer
in layoutSubviews
which means that every time an animation occurs it gets call.
Try commenting line 91 and you are going to get what you want.
Upvotes: 1