到目前为止,咱们已经见识了经过按钮点击触发的动画。其实,触发动画的办法不仅限于按钮点击。在本章中,您将学习多种不同的动画发动办法。
按钮(Button)
再回忆下按钮触发动作的办法,如下例:
经过「点击」按钮,改动「变量」,变量的改动导致了「可渐变特点」(比如Opacity、RotationEffect、ScaleEffect)跟着改动,最后经过.animation
修饰符告知 SwiftUI,跟踪变量,核算「插值」,实现「动」画作用。
挑选器(Picker)
Picker
组件常用于从一系列「选项」中进行「挑选」,例如可以实现滑动视图的作用:
@State var selection: Int = 0
VStack {
Picker("色彩", selection: $selection) {
Text("绿色").tag(0)
Text("赤色").tag(1)
}.pickerStyle(.segmented)
ZStack {
Color.green
//当选中时,横坐标从 -500 移动到 0,反之从 0 到 -500
.offset(x: selection == 0 ? 0 : -500)
Color.red
//当选中时,横坐标从 500 移动到 0,反之从 0 到 500
.offset(x: selection == 1 ? 0 : 500)
}
}.animation(.easeIn, value: selection)
.padding()
滑块(Slider)
Slider
组件用于从接连值范围内挑选一个值,例如可以增加一点动画的履行间隔,让动画有一点小小的滞后感:
HStack {
Color.orange.frame(width: state * 400)
Color.green
}.animation(.linear(duration: 3), value: state)
Slider(value: $state)
计步器(Stepper)
计数器可以「增减」数值,很容易与动画合作产生「值变」的动画作用,如下例:
ZStack {
ForEach(0..<100, id: .self){index in
Circle().fill(.cyan.gradient.opacity(0.5)).frame(width: CGFloat.random(in: state...50)).position(x: CGFloat.random(in: state...300), y: CGFloat.random(in: state...600))
}
}.animation(.easeInOut, value: state)
Stepper("Stepper", value: $state)
出现后(On Appear)
onAppear
常常应用于页面加载后履行一些初始化的动作或办法,用于动画时,常应用于开屏动画,例如:
View.onAppear() {
loading.toggle()
}
}
消失后(On Disappear)
onAppear
常常应用于页面关闭后履行一些销毁的动作或后置的办法,用于动画时,常应用于保存后的等候作用,例如:
View.onDisappear(){
refreshWhenFormDisappear = true
}
点击(TapGesture)
跟按钮(Button)有相似的用法,不过除了单击,它还是支撑多次点击(比如双击)触发事情,例如双击扩大或缩小:
Circle()
.fill(.blue.gradient)
.frame(width: 150)
.overlay(content: {
Text("双击")
.font(.title)
.foregroundStyle(.white)
})
// 扩大 2 倍
.scaleEffect(changed ? 2 : 1)
.animation(.easeIn, value: changed)
//监听「双击」事情
.onTapGesture(count: 2, perform: {
changed.toggle()
})
拖拽(DragGestures)
拖拽常用于将视图拖拽到一定的「程度」(超过某个值)后,触发一个动画事情,比如实现一个相似于 Sheet 的经过拖拽打开的作用:
View
.frame(height: offset > 500 ? 500 : offset < 200 ? 200 : offset)
.gesture(
DragGesture()
.onChanged({ value in
offset = offset - value.location.y
})
).animation(.easeIn, value: offset)
缩放(MagnificationGesture)
一般用于图片的缩放,如下例:
Image("demo")
.resizable()
.frame(width: 200, height: 200)
.scaleEffect(scale)
.gesture(MagnifyGesture()
.onEnded({ value in
//经过手势扩大或缩小图片
scale = value.magnification
})
).animation(.linear, value: scale)
旋转(RotationGesture)
当给旋转事情增加动画后,会产生流通的「翻滚」作用,如下例:
Image(systemName: "gear")
.font(.system(size: 200))
.foregroundStyle(.green)
.rotationEffect(.degrees(degree))
.animation(.linear, value: degree)
.gesture(RotateGesture()
.onEnded({ angle in
degree = degree + angle.rotation.degrees
})
)
滑动(ScrollView)
ScrollView {
ZStack {
GeometryReader(content: { geometry in
Image("mh")
.resizable()
.scaledToFill()
.offset(y: -geometry.frame(in: .global).origin.y * 0.5)
})
VStack(spacing: 50){
ForEach(0..<15, id: .self){index in
RoundedRectangle(cornerRadius: 25.0)
.fill(.ultraThinMaterial)
.frame(width: 300, height: 100)
}
}
}
}.ignoresSafeArea()
这段代码中的动画作用是由 GeometryReader
和 offset
的组合产生的。具体来说,这种动画作用是因为 offset
修饰符使用了 GeometryReader
提供的 geometry.frame(in: .global).origin.y
值来动态调整图片的 y
偏移量。这里逐步解释一下各个部分是怎么作业的:
GeometryReader 的作用
-
GeometryReader
用于获取其内容当时的尺度和方位。在这个比如中,它用来监控Image
组件的全局方位(global
坐标空间)。 -
geometry.frame(in: .global).origin.y
表示Image
在全局坐标空间中的 y 轴起始方位。当你翻滚ScrollView
时,这个值会改动,因为图画视图在屏幕上的方位在改变。
offset
修饰符的作用
-
offset(y: -geometry.frame(in: .global).origin.y * 0.5)
用于依据GeometryReader
读取到的 y 坐标来动态设置图片的偏移。这里的* 0.5
是一个缩放因子,意味着图片的翻滚速度是翻滚视图的一半。 - 这种偏移办法常被用来创立视差翻滚作用(parallax effect),即背景以比前景更慢的速度移动,从而增加深度感和动态作用。
动画作用的产生
- 当
ScrollView
被滑动时,geometry.frame(in: .global).origin.y
的值会跟着滑动的间隔发生改变。因而,Image
的offset
也会相应地动态改动。 - 虽然这段代码没有显式增加动画修饰符(如
.animation()
),滑动时图画方位的接连改动创立了一种滑润的视觉改变,看起来像是动画作用。这是由 SwiftUI 的烘托系统自动处理的,它优化了视图更新,使改变看起来滑润。