这次,我想将您已经单独理解的两件事放在一起,但是放在一起可能会有点伤脑筋。
之前,我们研究了修饰符的顺序的重要性。因此,如果我们这样编写代码:
Button("Tap Me") {
// do nothing
}
.background(Color.blue)
.frame(width: 200, height: 200)
.foregroundColor(.white)
结果将看起来与这样的代码不同:
Button("Tap Me") {
// do nothing
}
.frame(width: 200, height: 200)
.background(Color.blue)
.foregroundColor(.white)
这是因为如果我们在调整Frame之前为背景着色,则仅对原始空间着色,而不对扩展空间着色。如果您还记得的话,其根本原因是SwiftUI用修饰符包装视图的方式,使我们可以多次应用相同的修饰符——我们多次重复执行background()
和padding()
来创建条纹边框效果。
这就是概念一:修饰符顺序很重要,因为SwiftUI会按照修饰符的应用顺序包装视图。
概念二是我们可以对视图应用animation()
修饰符,以使其隐式地对更改进行动画处理。
为了演示这一点,我们可以修改按钮代码,以便根据某些状态显示不同的颜色。首先,我们定义状态:
@State private var enabled = false
在按钮的Action中我们可以在true和false之间进行切换:
self.enabled.toggle()
然后,我们可以在background()
修饰符内使用一个条件值,这样按钮可以是蓝色或红色:
.background(enabled ? Color.blue : Color.red)
最后,我们向按钮添加animation()
修饰符以使这些更改具有动画效果:
.animation(.default)
如果您运行该代码,则会看到点击按钮会在蓝色和红色之间为其设置动画的颜色。
因此:顺序修饰符很重要,我们可以将一个修饰符多次附加到视图上,并且可以通过animation()
修饰符使隐式动画发生。到目前为止都清楚吗?
那好。保护号自己,因为这可能会让你受伤。
您可以多次附加animation()
修饰符,并且使用顺序很重要。
为了说明这一点,我希望您在所有其他修饰符之后将这个修饰符添加到按钮中:
.clipShape(RoundedRectangle(cornerRadius: enabled ? 60 : 0))
这将导致按钮根据enabled
的布尔值的状态在正方形和圆角矩形之间变化。
运行该程序时,您会发现点击按钮会使其在红色和蓝色之间进行动画处理,但是会在正方形和圆角矩形之间进行跳转——该部分不会进行动画处理。
希望您能看到下一步:我希望您将clipShape()
修饰符移到动画之前,如下所示:
.frame(width: 200, height: 200)
.background(enabled ? Color.blue : Color.red)
.foregroundColor(.white)
.clipShape(RoundedRectangle(cornerRadius: enabled ? 60 : 0))
.animation(.default)
现在,当您运行代码时,背景颜色和剪辑形状都将进行动画处理。
因此,我们应用动画的顺序很重要:只有在animation()
修饰符之前发生的更改会变添加动画。
现在,有趣的部分是:如果我们应用多个animation()
修饰符,则每个修饰符都会控制所有内容,直到下一个动画为止。这使我们能够以各种不同的方式为状态变化设置动画,而不是为所有属性统一设置。
例如,我们可以使用默认动画来进行颜色更改,但是对形状改变使用弹簧效果:
Button("Tap Me") {
self.enabled.toggle()
}
.frame(width: 200, height: 200)
.background(enabled ? Color.blue : Color.red)
.animation(.default)
.foregroundColor(.white)
.clipShape(RoundedRectangle(cornerRadius: enabled ? 60 : 0))
.animation(.interpolatingSpring(stiffness: 10, damping: 1))
您可以根据需要在构造设计时使用任意数量的animation()
修饰符,这使我们可以将一种状态更改分成所需的多个分段。
为了更好的控制,可以通过将nil
传递给修饰符来完全禁用动画。例如,您可能希望颜色立即发生变化,但剪辑形状保留其动画,在这种情况下,您可以这样编写:
Button("Tap Me") {
self.enabled.toggle()
}
.frame(width: 200, height: 200)
.background(enabled ? Color.blue : Color.red)
.animation(nil)
.foregroundColor(.white)
.clipShape(RoundedRectangle(cornerRadius: enabled ? 60 : 0))
.animation(.interpolatingSpring(stiffness: 10, damping: 1))
没有多个animation()
修饰符将无法实现这种控制——如果您尝试在动画之后去改变background()
,您会发现它只会撤消clipShape()
的工作。
Button("Tap Me") {
self.enabled.toggle()
}
.frame(width: 200, height: 200)
.background(enabled ? Color.blue : Color.red)
.foregroundColor(.white)
.clipShape(RoundedRectangle(cornerRadius: enabled ? 60 : 0))
.animation(.interpolatingSpring(stiffness: 10, damping: 5))
.background(enabled ? Color.blue : Color.red)
最终的的形状将会是一成不变的矩形。
译自Controlling the animation stack
Previous: 创建显式动画 | Hacking with iOS: SwiftUI Edition | Next: 动画手势 |
---|
赏我一个赞吧~~~