2

My button is being resized by using auto layout. The button has a CAShapeLayer which it's frame is being set at layoutSubviews:

var initial = true

override func layoutSubviews() {
    super.layoutSubviews()

    if initial {
        border.frame = layer.bounds
        border.path = UIBezierPath(rect: bounds).CGPath

        initial = false
    }
}

Because of this, whenever the size of this button is changed, the layer is changed immediately without any animation (which hides the button animation itself).

I've tried to add an animation:

override func layoutSubviews() {
    super.layoutSubviews()

    func movePosition() {
        let fromValue = border.position.x
        let toValue = center.x

        CATransaction.setDisableActions(true)
        border.position.x = toValue

        let positionAnimation = CABasicAnimation(keyPath: "position.x")
        positionAnimation.fromValue = fromValue
        positionAnimation.toValue = toValue
        positionAnimation.duration = 0.5

        border.addAnimation(positionAnimation, forKey: "position")
    }

    func changesWidth() {
        let fromValue = border.frame.size.width
        let toValue = layer.bounds.width

        CATransaction.setDisableActions(true)
        border.frame.size.width = toValue

        let widthAnimation = CABasicAnimation(keyPath: "frame.size.width")
        widthAnimation.fromValue = fromValue
        widthAnimation.toValue = toValue
        widthAnimation.duration = 0.5

        border.addAnimation(widthAnimation, forKey: "width")
    }

    if initial {
        border.frame = layer.bounds
        border.path = UIBezierPath(rect: bounds).CGPath

        initial = false
    } else {
        movePosition()
        changesWidth()
    }
}

But with this, the animation is totally messed up (and layoutSubview is called a few times initially so it messes the layers up at the start.

Is it right to be trying to animate the layer in layoutSubviews at all? Or should I calculate the widths manually and animate the layers from there?

Henny Lee
  • 2,970
  • 3
  • 20
  • 37
  • Seen this? http://stackoverflow.com/questions/24303279/auto-layout-constraint-on-calayer-ios – Robert Gummesson Mar 28 '16 at 10:55
  • 1
    Yes. But instead of animating the layer, it will just changed instantly. – Henny Lee Mar 28 '16 at 11:03
  • ...and the button is not? How are you animating the button? Using a UIView animation? – Robert Gummesson Mar 28 '16 at 11:08
  • Yes, I change the auto layout and then I call `UIView.animateWithDuration(0.5) { self.layoutIfNeeded }`. – Henny Lee Mar 28 '16 at 11:09
  • 1
    Right, then it will get tricky. You can't always sync a CABasicAnimation with a UIView animation as you are attempting already. The problem is that you need to reassure your animations are cancelled if the UIView animation is. You will also have limits. What happens if the animation duration changes? What if you want to use a spring damping animation?... What is your CAShapeLayer for? If you can replace your shapes with Core Graphics called on drawRect, life will become a lot easier. – Robert Gummesson Mar 28 '16 at 11:25

0 Answers0