Trigger:动画的激活方式

到目前为止,我们已经见识了通过按钮点击触发的动画。其实,触发动画的方法不仅限于按钮点击。在本章中,您将学习多种不同的动画启动方式。

按钮(Button)

再回顾下按钮触发动作的方式,如下例:

通过「点击」按钮,改变「变量」,变量的改变导致了「可渐变属性」(比如Opacity、RotationEffect、ScaleEffect)跟着改变,最后通过.animation修饰符告知 SwiftUI,跟踪变量,计算「插值」,实现「动」画效果。

选择器(Picker)

Picker 组件常用于从一系列「选项」中进行「选择」,例如可以实现滑动视图的效果:

swift 复制代码
@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 组件用于从连续值范围内选择一个值,例如可以增加一点动画的执行间隔,让动画有一点小小的滞后感:

swift 复制代码
HStack {
	Color.orange.frame(width: state * 400)
	Color.green
}.animation(.linear(duration: 3), value: state)

Slider(value: $state)

计步器(Stepper)

计数器可以「增减」数值,很容易与动画配合产生「值变」的动画效果,如下例:

swift 复制代码
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常常应用于页面加载后执行一些初始化的动作或方法,用于动画时,常应用于开屏动画,例如:

swift 复制代码
View.onAppear() {
		loading.toggle()
	}
}

OnAppear_Intro.swift

消失后(On Disappear)

onAppear常常应用于页面关闭后执行一些销毁的动作或后置的方法,用于动画时,常应用于保存后的等待效果,例如:

swift 复制代码
View.onDisappear(){
	refreshWhenFormDisappear = true
}

点击(TapGesture)

跟按钮(Button)有类似的用法,不过除了单击,它还是支持多次点击(比如双击)触发事件,例如双击放大或缩小:

swift 复制代码
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 的通过拖拽展开的效果:

swift 复制代码
View
	.frame(height: offset > 500 ? 500 : offset < 200 ? 200 : offset)
	.gesture(
		DragGesture()
			.onChanged({ value in
				offset = offset - value.location.y
			})
	).animation(.easeIn, value: offset)

DragGesture_Intro.swift

缩放(MagnificationGesture)

通常用于图片的缩放,如下例:

swift 复制代码
  Image("demo")
	.resizable()
	.frame(width: 200, height: 200)
	.scaleEffect(scale)
	.gesture(MagnifyGesture()
		.onEnded({ value in
			//通过手势放大或缩小图片
			scale = value.magnification
		})
	).animation(.linear, value: scale)

旋转(RotationGesture)

当给旋转事件添加动画后,会产生流畅的「转动」效果,如下例:

swift 复制代码
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)

swift 复制代码
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()

这段代码中的动画效果是由 GeometryReaderoffset 的组合产生的。具体来说,这种动画效果是因为 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 的值会随着滑动的距离发生变化。因此,Imageoffset 也会相应地动态改变。
  • 尽管这段代码没有显式添加动画修饰符(如 .animation()),滑动时图像位置的连续改变创建了一种平滑的视觉变化,看起来像是动画效果。这是由 SwiftUI 的渲染系统自动处理的,它优化了视图更新,使变化看起来平滑。
相关推荐
问道飞鱼1 分钟前
【移动端知识】移动端多 WebView 互访方案:Android、iOS 与鸿蒙实现
android·ios·harmonyos·多webview互访
mascon1 小时前
U3D打包IOS的自我总结
ios
名字不要太长 像我这样就好1 小时前
【iOS】继承链
macos·ios·cocoa
karshey2 小时前
【IOS webview】IOS13不支持svelte 样式嵌套
ios
潜龙95272 小时前
第4.3节 iOS App生成追溯关系
macos·ios·cocoa
游戏开发爱好者811 小时前
iOS App 电池消耗管理与优化 提升用户体验的完整指南
android·ios·小程序·https·uni-app·iphone·webview
神策技术社区18 小时前
iOS 全埋点点击事件采集白皮书
大数据·ios·app
wuyoula19 小时前
iOS V2签名网站系统源码/IPA在线签名/全开源版本/亲测
ios
2501_9159184119 小时前
iOS 性能监控工具全解析 选择合适的调试方案提升 App 性能
android·ios·小程序·https·uni-app·iphone·webview
fishycx19 小时前
iOS 构建配置与 AdHoc 打包说明
ios