[SwiftUI 100 天] Animations - part2
2020/3/30 23:02:35
本文主要是介绍[SwiftUI 100 天] Animations - part2,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
译自 Animating bindings
更多内容,欢迎关注公众号 「Swift花园」
喜欢文章?不如来个 🔺💛➕三连?关注专栏,关注我 🚀🚀🚀
动画化绑定
animation()
modifier 可以应用到任何的 SwiftUI 绑定,以动画方式呈现绑定的值从当前值到新值的变化。即使这个数据看起来不像能以动画呈现的类型,动画也能工作。比如一个布尔型 —— 你可以想象从 1.0 到 2.0 的动画过程,是因为我们可以想象 1.05 ,1.1,1.15 这样的数值,但是从 “false” 到 “true” 听起来没有留给动画的空间。
要想解释这个问题,最好是通过代码。下面上代码:
struct ContentView: View { @State private var animationAmount: CGFloat = 1 var body: some View { VStack { Stepper("Scale amount", value: $animationAmount.animation(), in: 1...10) Spacer() Button("Tap Me") { self.animationAmount += 1 } .padding(40) .background(Color.red) .foregroundColor(.white) .clipShape(Circle()) .scaleEffect(animationAmount) } } }复制代码
提示: 如果你只想要一个文本标题,可以用最简单的 Stepper
构造器,方式跟按钮差不多。
如你所见, stepper 可以在 animationAmount
上下变化,点击按钮也会添加这个数值 —— 两个控件绑定了相同的数据。所以操作一个控件也会影响另一个。不过,点击按钮会立即改变animationCount
,所以按钮会立即变大。相对的, stepper 被绑定到 $animationAmount.animation()
,意味着 SwiftUI 会动画呈现数值的变化。
现在,作为实验,我希望你把 body 属性改成下面这样:
var body: some View { print(animationAmount) return VStack {复制代码
因为这里有非视图代码,所以我们需要在 VStack
之前添加一个 return ,以便 Swift 理解哪一部分是要返回的视图。这里新增的 print(animationAmount)
很重要。我需要你再次运行程序,操作 stepper 。
你应该会看到打印输出 2.0 ,3.0 ,4.0 ,等等。与此同时,按钮会平滑地放大缩小 —— 它不再直接跳变到 2 倍,3 倍,4 倍这些大小了。这里面发生的事情是:SwiftUI 在绑定发生变化之前检查了视图的状态,在绑定发生变化之后也检查了视图的状态,然后应用了一个从点 A 到 点 B 的动画。
这正是为什么我们可以动画呈现一个布尔型变化过程的原因:Swift 并没有在 false 和 true 之间发明了新值,只不过动画演示了布尔值改变发生前后两个视图的变化。
这些动画绑定使用我们在视图上使用的一样的 animation()
modifier ,所以如果你需要,可以深入到 animation modifier 内部去定制:
Stepper("Scale amount", value: $animationAmount.animation( Animation.easeInOut(duration: 1) .repeatCount(3, autoreverses: true) ), in: 1...10)复制代码
这些动画绑定有效地引入了动画,它不是通过在视图上设置动画并用隐式动画呈现状态的变化,而是直接显式地把动画直接设置在状态上。在前者中,状态变化并不知道自己会触发动画,而在后者中则是视图不知道自己会被动画呈现 —— 两种方式都能工作而且都很重要。
译自 Creating explicit animations
创建显式动画
你已经掌握 SwiftUI 让我们创建隐式动画的方式了 —— 把 animation()
modifier 添加到视图,并且它也可以通过添加animation()
modifier 到绑定的方式直接创建动画绑定,但这里还有一种创建动画的方式:显式要求 SwiftUI 动画演示状态的变化。
这并不意味着我们要手工创建动画的每一帧 —— 那还是 SwiftUI 的工作,并且工作机制还是找出视图状态变化前后的动画。
不过,我们现在是要显式表明动画发生在任意一个特定属性的状态发生改变时:它不是附加在绑定上,也不是附加在视图上,而是在某个状态变化时显式请求特定动画。
为了演示这一点,让我们回到一个简单按钮的例子:
struct ContentView: View { var body: some View { Button("Tap Me") { // do nothing } .padding(50) .background(Color.red) .foregroundColor(.white) .clipShape(Circle()) } }复制代码
当按钮被点击时,我们要让它以一种 3D 效果的方式旋转。这里用又一个新的 modifier , 叫rotation3DEffect()
。我们传给这个 modifier 一个给定的旋转角度,以及确定视图如何旋转的坐标轴。你可以把这个坐标抽想象成穿过一根穿过你的视图的 “串肉扦” :
- 如果我们的 skewer 从 X 轴穿过视图 (水平穿过) ,那么视图将以 skewer 为轴,前后自转
- 如果我们的 skewer 从 Y 轴穿过视图 (竖直穿过) ,那么视图将以 skewer 为轴,左右自转
- 如果我们的 skewer 从 Z 轴穿过视图 (纵深穿过) , 那么视图将以 skewer 为轴,左右旋转
注意,这里区分自转和旋转,主要是因为视图在 X 和 Y 方向上有明显的大小,在 Z 轴上则可以近似看作没有厚度。想象一下画面,你就能理解。
要实现旋转,还需要一个添加一个属性,因为旋转度数要求一个Double
:
@State private var animationAmount = 0.0复制代码
接下来,我们要让按钮以 animationAmount
作为度数沿着 Y 轴自转,也就是左右转。把下面的 modifier 添加到按钮:
.rotation3DEffect(.degrees(animationAmount), axis: (x: 0, y: 1, z: 0))复制代码
现在是重要的部分:我们要给按钮的 action 添加一些代码,每当按钮被点击时让 animationAmount
增加 360 。
如果我们直接写 self.animationAmount += 360
,那么变化会直接发生,因为没有给按钮附加 modifier 。这里正是显式动画可以发挥的地方:在 SwiftUI 中我们用一个叫 withAnimation()
的闭包来确保状态改变通过动画来呈现。
在按钮的 action 中添加下面的代码:
withAnimation { self.animationAmount += 360 }复制代码
运行代码,我相信你会对 app 的效果印象深刻 —— 每当你点击按钮,你会在 3D 空间里自转,而我们实现这个效果的代码是如何简单。如果你有时间,可以自行尝试一下不同的坐标轴,这样你就会真正理解旋转动画的工作方式。我想你可能会好奇,这里告诉你,你可以同时使用不只一个坐标轴哦。
withAnimation()
还可以传入一个参数,指定你在 SwiftUI 中其他地方可以用到的任何动画。举个例子,我们可以让旋转效果使用一个弹簧动画,代码就像这样:
withAnimation(.interpolatingSpring(stiffness: 5, damping: 1)) { self.animationAmount += 360 }复制代码
我的公众号 这里有Swift及计算机编程的相关文章,以及优秀国外文章翻译,欢迎关注~
这篇关于[SwiftUI 100 天] Animations - part2的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2022-10-05Swift语法学习--基于协议进行网络请求
- 2022-08-17Apple开发_Swift语言地标注释
- 2022-07-24Swift 初见
- 2022-05-22SwiftUI App 支持多语种 All In One
- 2022-05-10SwiftUI 组件参数简写 All In One
- 2022-04-14SwiftUI 学习笔记
- 2022-02-23Swift 文件夹和文件操作
- 2022-02-17Swift中使用KVO
- 2022-02-08Swift 汇编 String array
- 2022-01-30SwiftUI3.0页面反向传值