Section 10 : Animation Between Screens

Section 10 : Animation Between Screens - 屏幕间动画(13’26")

Create a transition between two views.

创建两个视图之间的动画过渡。

1. 创建 Home 视图

现在我们来创建一个新的视图,来调用上一节的 MenuView 视图。

(1)新建文件 Home。修改默认的文本内容和修饰并用 HStack 包裹起来。

(2)在文本的下方,创建一个按钮 (Button)。

创建这些内置的组件的方法有两种:

  • 直接输入代码,这要求你对 SWiftUI 足够的熟悉。

  • 使用快捷键⌃ ⌘ L,呼出组件窗口,找到合适的组件并双击,Xcode 会输入一段默认的代码。比如按钮,

Button(action: {}) {
	Text("Button")
}

其中 Text("Button") 是按钮显示的部分,action: {}是按钮的功能部分(在花括号里面写点击按钮的动作响应)。这里我们用图片 wowLM_small 代替文本。同样有两种方法来建立图片。

(3)插入图片后,我们会发现预览中图片没正常显示出来,这是因为默认渲染的方式不适合图片,需要给图片加上渲染模式的修饰。之后再加上必要的修饰调整。

Button(action: {}) {
    Image("wowLM_small")
        .renderingMode(.original)           // 修改渲染模式,保证图片正常显示
        .resizable()
        .frame(width: 36, height: 36)
        .clipShape(Circle())
}

🛠小窍门

当鼠标移动到某个圆括号或者花括号(无论哪边)时,Xcode 会高亮闪烁对应的另一半大概 1 秒钟。这样可以迅速地配对,便于查找忘记关闭括号的错误。

(4)在图片和按钮之间增加 Spacer 占位,让二者向左右撑开。并加上适当的边距修饰。

(5)将 HStack 用 VStack 包裹后,通过 Spacer 占位让整个 HStack 能在屏幕顶端显示,同时会让 VStack 充满整个屏幕(在预览中单击空白处可以看到,或者在编辑器里面单击 VStack)。

(6)现在需要将 MenuView 和 VStack 堆叠起来,所以要先创建一个 ZStack 容器。按住⌘点击 VStack,在快捷菜单中选择 Embed in VStack,然后将 VStack 改为 ZStack。这么做的好处是,基本上可以避免忘记关闭括号的错误(或者在错误的地方关闭括号)。 注意大小写哟,这个招数我们在前面的章节其实已经用过了。

(7)将 MenuView 视图添加到 ZStack。后面我们将称这里的 VStack 为主屏幕。

2. 制作 MenuView 动画

(1)在 body 之前声明用于控制动画的状态变量 showProfile 并指定默认值为 false 。

@State var showProfile = false		// 声明控制动画的状态变量

(2)前面章节曾经使用了手势 TapGesture 来响应点击后的动画。因为这里有了按钮组件,所以直接在按钮组件的 action 中设计需要响应的内容就好。

Button(action: {self.showProfile.toggle()}) {   // 按钮单击响应,切换 showProfile 状态
    Image("wowLM_small")
        .renderingMode(.original)           	// 修改渲染模式,保证图片正常显示
        .resizable()
        .frame(width: 36, height: 36)
        .clipShape(Circle())
}

现在点击头像可以正常地显示或隐藏 MenuView,但是还没有动画。

(3)给 MenuView 加上动画

 MenuView()
	.offset(y: showProfile ? 0 : 600)
	.animation(.spring(response: 0.5, dampingFraction: 0.6, blendDuration: 0))

3. 设置背景

(1)先给整个屏幕设置个底色。

使用 Color (因为它是个 View,所以能直接作为栈中的组件使用,还记得不?)放在最底层(ZStack 中的代码的最前面),使用 color literal 选择顶栏左边第二个颜色(仅次于白色的灰色)。由于其他层都没有底色(透明的),所以我们能在预览中看到底层的颜色了。但是由于 iOS 默认对屏幕做了一些限制,即所谓的安全区域,使得底色没有充满整个屏幕。这需要加上 edgesIgnoringSafeArea 修饰。

ZStack {
	// ZStack 最前面,即最底层
	Color(#colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1))
		.edgesIgnoringSafeArea(.all)    // 忽略安全区域,满屏
	/**
	其他各层代码(略)
	*/
}

(2)给主屏幕层设定背景色,先设定 background 修饰,再加上 edgesIgnoringSafeArea 修饰。这个时候我们发现出事了,由于整个 VStack 忽略了安全区域,撑满的效果让标题和头像都和安全区域重叠了。没关系,给它加个 padding 就好了。

VStack{
    // 代码略
}
.padding(.top, 44)                  // 让出安全区域(这是 iPhone 11 Pro 的数据)
.background(Color.white)            // 主屏幕的背景颜色
.edgesIgnoringSafeArea(.all)        // 忽略安全区域,填满屏幕

不同设备的安全区域是不同的,类似上面使用 padding 修饰的硬编码方式……不能自适应设备,这个问题后面会说到的。所以建议尽量分层使用扩展到安全区域,而不是只在 ZStack 上使用,因为:

  • 不是所有的视图层都需要扩展到安全区域
  • 将容器扩展到安全区域会影响到里面的所有组件

4. 设置动画

先贴代码,然后说心得。

VStack {        							// 主屏幕
	// 代码略
}
    .padding(.top, 44)                      // 让出安全区域(这是 iPhone 11 Pro 的数据)
    .background(Color.white)                // 主屏幕的背景颜色
    .clipShape(RoundedRectangle(cornerRadius: 30, style: .continuous))
    .shadow(color: Color.black.opacity(0.2), radius: 20, x: 0, y: 20)
    .offset(y: showProfile ? -450 : 0)
    .rotation3DEffect(Angle(degrees: showProfile ? -10 : 0), axis: (x: 10, y: 0, z: 0))
    .scaleEffect(showProfile ? 0.9 : 1)     // 使用 showProfile 控制缩放效果
    .animation(.spring(response: 0.5, dampingFraction: 0.6, blendDuration: 0))
    .edgesIgnoringSafeArea(.all)            // 忽略安全区域,填满屏幕

说说大叔的心得哈。我觉得这类工作应该按下面的顺序进行比较好。

  • 先将 body 前面的状态变量默认值改为 true,这样预览默认显示的是点击按钮后的效果。
  • 逐个修饰器往上加,逐步调整好细节。
  • 添加动画修饰。
  • 将状态变量默认值改回 false。

本节小结

本节代码请参见 GitHub码云

  • ⌃ ⌘ L 快捷键呼出对话框创建组件,在不熟悉 SWiftUI 的时候是个好主意。
  • 像在 Photoshop 等软件中那样考虑图层。
  • edgesIgnoringSafeArea 可以扩展组件到安全区域,但如果加在 Stack 类容器会影响到里面的子组件。
  • 安全区域因设备不同而不同。
  • 先效果,再动画。
接下来

发现没?你点了按钮以后就锁住了……回不去了——因为没有什么按钮或者手势让你操作了。没关系,我们下一节解决这个问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值