Animation changes during the rotation of the device based on the size element will be after the rotation is completed

I have a dynamic button configuration that automatically adjusts to the width and height based on the auto layout restrictions set in the storyboard. When the buttons in the portrait have equal width and height, so that the frame is perfectly square, and when the device rotates into the landscape, the buttons become shorter and wider. I set cornerRadius on the button layers so that they are completely circular when they were in the portrait, and it works well, but when I turn to the landscape, the corner radius clearly doesn't look right. I need to change this so that it becomes oval. The problem is that no matter where I try to put this code, I can not get the correct width and height of the buttons after the rotation. I want this to happen during the rotation of the device - do not want to wait for the rotation to complete. Ideally, cornerRadius will animate the change during the transition animation.

If I use viewWillLayoutSubviews or viewDidLayoutSubviews , it gets the button frame correctly when the application starts, but when turning to the album, this method is called before the button frame is updated for the new orientation, t calculate the correct angular radius.

If I use viewWillTransitionToSize:withTransitionCoordinator: or willTransitionToTraitCollection:withTransitionCoordinator: or willRotateToInterfaceOrientation , it is not called when the application starts, and when it is rotated, it is called before the frame is updated for the new size.

If I use willAnimateRotationToInterfaceOrientation , it is not called when the application starts, but when the device is rotated, it correctly receives a new button frame. But this method is outdated.

So the question is, what method can you use to set the button properties based on the size of the button when the rotation is completed, which is called before the rotation is completed?

Please note that you need to call it for every change of orientation, and not just for changing the class size (the rotating iPad does not change the class size). I only need to support iOS 8.0 +.

This is the code that I put in the methods to find out if it gets the correct size:

 println("\(button.frame.size.width) x \(button.frame.size.height)") 
+8
ios ios8 swift size-classes screen-rotation
source share
2 answers

Below I will describe how you can use CADisplayLink to update properties during each frame of the animation, but there is an easier way. A subclass of the button (or view or something else) with layoutSubviews that updates the corner radius:

 class RoundedCornerView: UIView { override func layoutSubviews() { super.layoutSubviews() layer.cornerRadius = min(bounds.width, bounds.height) / 2 } } 

Then, during the animation, when the frame size changes, the corner radius is automatically updated:

enter image description here


As Joey notes, you can use viewWillTransitionToSize to notify you of a new size, and then use animateAlongsideTransition to coordinate your additional animation along with the main animation.

If you want to animate a non-animated property, such as an angular radius (in a block-based animation, anyway), you can use the link to display throughout the animation. This effectively calls our method for each frame of the rotation animation. so we’ll have a method that looks at the presentation level (which shows the current state of the middle layer animation) to adjust the radius of the angle on the fly. You can use animateAlongsideTransition for this, but we do not use the animation closure in this case, but simply use the completion closure to find out when the animation is complete and therefore can stop the display link:

 override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator) let displayLink = CADisplayLink(target: self, selector: "handleDisplayLink:") displayLink.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes) coordinator.animateAlongsideTransition(nil) { (context) -> Void in displayLink.invalidate() } } func handleDisplayLink(displayLink: CADisplayLink) { updateButtonsCornerRadius() } func updateButtonsCornerRadius() { for button in [button1, button2] { let presentationLayer = button.layer.presentationLayer() as CALayer let minDimension = min(presentationLayer.frame.size.width, presentationLayer.frame.size.height) button.layer.cornerRadius = minDimension / 2.0 } } 

Frankly, I'm not sure that this angular radius animation is enough to justify this link (I had to slow down the animation in the simulator using command + T to appreciate the difference), but this illustrates the basic idea.

+6
source share

The answer is to use viewWillTransitionToSize:withTransitionCoordinator: with code placed inside the animation closure of the UIViewControllerTransitionCoordinator animateAlongsideTransition: method. This will allow you to animate the changes depending on the size that will be upon completion of the rotation.

 override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator) coordinator.animateAlongsideTransition({ (context: UIViewControllerTransitionCoordinatorContext!) -> Void in self.updateButtonsCornerRadius() }, completion: nil) } 

This method is not called when the application starts, so you also want to call self.updateButtonsCornerRadius() in viewDidLoad .

+4
source share

All Articles