基于size元素的设备旋转期间的动画更改将在旋转完成后进行 [英] Animate changes during device rotation based on size element will be after rotation completes

查看:163
本文介绍了基于size元素的设备旋转期间的动画更改将在旋转完成后进行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个动态的按钮设置,可根据故事板中设置的自动布局约束自动调整宽度和高度。在纵向时,按钮具有相等的宽度和高度,因此框架是完全正方形的,当设备旋转到横向时,按钮变得更短更宽。我已经在按钮的图层上设置了 cornerRadius ,因此它们在纵向时非常圆,并且运行良好,但是当我旋转到横向时,角半径看起来不正确显然。我需要改变它,所以它变成了椭圆形。问题是,无论我在哪里尝试放置代码,我都无法获得旋转发生后按钮的正确宽度和高度。我希望在旋转设备时发生这种情况 - 不想等到旋转完成。理想情况下, cornerRadius 会在转换动画时设置更改动画。

I have a dynamic setup of buttons that automatically adjust in width and height based on auto layout constraints set up in a storyboard. When in portrait the buttons have equal widths and heights so the frame is perfectly square, and when the device is rotated to landscape the buttons get shorter and wider. I have set cornerRadius on the buttons' layers so they're perfectly circular when in portrait and that works well, but when I rotate to landscape the corner radius doesn't look right anymore obviously. I need to change that so it becomes an oval. The problem is, no matter where I try to put that code, I cannot get the correct width and height the buttons will be after the rotation occurs. I want this to occur while the device is being rotated - don't want to wait until the rotation has completed. Ideally the cornerRadius would animate the change while the transition animates.

如果我使用 viewWillLayoutSubviews viewDidLayoutSubviews ,它在应用程序启动时正确获取按钮框架,但在旋转到横向时,在按钮的框架更新之前调用此方法对于新的方向,所以我无法计算正确的角半径。

If I use viewWillLayoutSubviews or viewDidLayoutSubviews, it correctly gets the button frame when the app is launched, but upon rotating to landscape this method is called before the button's frame is updated for the new orientation, so I can't calculate the correct corner radius.

如果我使用 viewWillTransitionToSize:withTransitionCoordinator: willTransitionToTraitCollection:withTransitionCoordinator: willRotateToInterfaceOrientation ,它在应用程序启动时不会被调用,并且在旋转时在为新大小更新帧之前调用它的设备。

If I use viewWillTransitionToSize:withTransitionCoordinator: or willTransitionToTraitCollection:withTransitionCoordinator: or willRotateToInterfaceOrientation, it doesn't get called when the app is launched, and upon rotating the device it is called before the frame is updated for the new size.

如果我使用 willAnimateRotationToInterfaceOrientation ,它不会在启动应用程序时调用,但在旋转设备时,它会正确获取新的按钮框架。但是这个方法已被弃用。

If I use willAnimateRotationToInterfaceOrientation, it doesn't get called when the app is launched, but upon rotating the device it does correctly get the new button frame. But this method is deprecated.

所以问题是,你可以用什么方法根据按钮的大小来设置按钮的属性旋转已完成,在旋转完成之前调用?

请注意,需要为每个方向更改调用它,而不仅仅是尺寸类更改(旋转iPad不会改变尺寸等级)。我只需要支持iOS 8.0 +。

Note that it needs to be called for every orientation change, not just size class changes (rotating iPad doesn't change the size class). I only need to support iOS 8.0+.

这是我在方法中放置的代码,以确定它是否获得了正确的大小:

This is the code I'm placing in the methods to know if it is getting the correct size:

println("\(button.frame.size.width) x \(button.frame.size.height)")


推荐答案

下面我概述如何使用 CADisplayLink 在动画的每一帧中更新属性,但有一种更简单的方法。使用更新角半径的 layoutSubviews 对按钮(或视图或其他)进行子类化:

Below I outline how one could use a CADisplayLink to update the properties during every frame of the animation, but there is an easier way. Subclass the button (or view or whatever) with a 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, as the frame size changes, the corner radius is updated automatically:

正如Joey指出的那样,可以使用 viewWillTransitionToSize 来通知新的大小,然后使用 animateAlongsideTransition 来协调您的其他动画以及主动画。

As Joey points out, one can use viewWillTransitionToSize to be notified of the new size, and then use animateAlongsideTransition to coordinate your additional animation along with the main animation.

如果您想要动画一种不可动画的属性,例如角半径(无论如何,在基于块的动画中),您可以在动画持续时间内使用显示链接。这有效地为旋转动画的每一帧调用我们的方法。因此,我们将有一个方法来查看表示层(它向您显示动画中间层的当前状态)来动态调整角半径。您也可以使用 animateAlongsideTransition ,但在这种情况下我们不使用动画闭包,而是只使用完成闭包来知道动画何时完成,因此可以停止显示链接:

If you want to animate an un-animatable property, such as corner radius (in block-based animations, anyway), you can use a display link for the duration of the animation. This effectively calls our method for every frame of the rotation animation. thus, we'll have a method that looks at the presentation layer (which shows you the current state of a layer mid-animation) to adjust the corner radius on the fly. You can use animateAlongsideTransition for this, too, but we're not using the animation closure in this case, but rather merely using the completion closure to know when the animation is done 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
    }
}

坦白说,我不确定这个角半径动画是否足以证明这个显示链接的合理性(我不得不用减慢模拟器中的动画速度命令 + T 欣赏差异),但这说明了基本思路。

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

这篇关于基于size元素的设备旋转期间的动画更改将在旋转完成后进行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆