动画视图和过渡
使用SwiftUI时,无论效果在哪里,您都可以单独为视图或视图状态的更改添加动画效果。SwiftUI为您处理这些组合、重叠和可中断动画的所有复杂性。
在本教程中,您将为包含图表的视图制作动画,该视图用于跟踪用户在使用Landmarks应用程序时徒步旅行。使用animation(_:)修饰符,您将看到为视图制作动画是多么容易。
下载初学者项目并遵循本教程,或打开已完成的项目并自行探索代码。
第一节 将徒步旅行数据添加到应用程序中
在添加动画之前,您需要一些动画。在本节中,您将导入和建模徒步旅行数据,然后添加一些预构建的视图,以便在图表中静态显示该数据。
第一步 添加资源文件
下载初学者项目,在Resources文件下找到hikeData.json,拖入您的工程Resources目录下
第二步 创建模型Hike.swift
使用菜单项文件>新建>文件,在项目的模型组中创建一个名为Hike.swift的新Swift文件。
与Landmark结构一样,Hike结构符合Codable,并具有与相应数据文件中的键匹配的属性。
import Foundation
struct Hike: Codable, Hashable, Identifiable {
var id: Int
var name: String
var distance: Double
var difficulty: Int
var observations: [Observation]
static var formatter = LengthFormatter()
var distanceText: String {
Hike.formatter
.string(fromValue: distance, unit: .kilometer)
}
struct Observation: Codable, Hashable {
var distanceFromStart: Double
var elevation: Range<Double>
var pace: Range<Double>
var heartRate: Range<Double>
}
}
第三步 将hikes数组加载到您的模型对象中。
因为您在最初加载后永远不会修改徒步旅行数据,因此您无需使用@Published属性对其进行标记。
final class ModelData: ObservableObject {
@Published var landmarks:[Landmark] = load("landmarkData.json")
var hikes: [Hike] = load("hikeData.json")
}
第四步 添加Hikes资源文件
将Hikes文件夹从下载文件的资源文件夹拖到项目的视图组中。在单击完成之前,请务必选择“如果需要复制项目”和“创建组”。
第五步 预览
在HikeView.swift中,打开实时预览,并尝试显示和隐藏图表。
请务必在整个教程中使用实时预览,以便您可以尝试每个步骤的结果。
第二节 给视图添加动画
在等价视图上使用animation(:)修改器时,且视图的可动画属性发生变化时,swiftUI会生成一个动画。
视图的颜色、不透明度、旋转、大小和其他属性都可以设置动画。当视图不等价,可以使用animation(:value:)修改器在指定值更改时启动动画。
第一步 按钮旋转时添加动画
在HikeView.swift中,通过添加一个动画修饰器,当showDetail的值发生变化时,按钮开始旋转,
.animation(.easeInOut, value: showDetail)
第二步 按钮添加放大动画
当图形可见时,给按钮添加一个放大动画
.scaleEffect(showDetail ? 1.5 : 1.0)
第三步 更改动画类型
把动画类型easeInOut改成 spring().
.animation(.spring(), value: showDetail)
swiftUI包括预定义或自定义的基础动画,以及弹簧和流体动画。可以调整动画的速度,在动画开始前设置延迟,或者指定动画重复
第四步 关闭旋转动画
在scaleEffect修饰器上方再添加一个动画修饰器,动画类型设置成nil
.animation(nil, value: showDetail)
第五步 移除动画修饰器
在进行下一步之前,先移除之前添加的两个动画修饰器
第三节 状态变化时生成动画
现在您已经学会了如何给某个视图添加动画,是时候根据状态变化添加动画了。
在这里,您将对用户点击按钮并切换showDetail状态属性时发生的所有更改应用动画。
第一步 使用withAnimation
用withAnimation函数包装showDetail.toggle()的调用。 受showDetail属性影响的两个视图(按钮和HikeDetail视图)现在都有动画过渡。
第二步 设置动画时长
传递一个4秒时间的基础动画,您可以传递和animation(_:value:)相同的动画
第三步 在动画的过程中,尝试打开和关闭图形视图
在进行下一步之前,先清除withAnimation的参数
第四节 自定义转场动画
默认情况下,视图的转场效果是渐隐渐现的,您可以通过transition(_:)修饰器来自定义转场动画
第一步 给HikeView.swift 添加一个transition(_:)修饰器
if showDetail { HikeDetail(hike: hike) .transition(.slide)
现在图形展示和消失都会有滑动效果了
第二步 提取转场代码
提取刚刚添加为AnyTransition静态属性的转场,并在视图的转场修改器中访问新属性。
当您扩展自定义转场时,这将使您的代码尽可能的干净
extension AnyTransition {
static var moveAndFade: AnyTransition {
AnyTransition.slide
}
}
第三步 切换slide->move(edge:)
使用slide图形从左侧滑入屏幕,右侧滑出屏幕, 将slide换成move(edge:),使视图滑入滑出都在左侧
extension AnyTransition {
static var moveAndFade: AnyTransition {
AnyTransition.move(edge: .trailing)
}
}
第四步 使用非对称修饰器 asymmetric(insertion:removal:)
当视图显示和消失时,使用asymmetric(insertion:removal:)可以提供不同的转场动画。比如:
显示时,需要从右侧进入,且伴随着透明度逐渐显示。
消失时,需要缩小,且伴随着透明度逐渐消失。
extension AnyTransition {
static var moveAndFade: AnyTransition {
.asymmetric(
insertion: .move(edge: .trailing).combined(with: .opacity),
removal: .scale.combined(with: .opacity))
}
}
第五节 为复杂的效果组合动画
单击条形图下方的按钮时,图形会在三组不同的数据之间切换。在本节中,您将使用合成动画为构成图形的胶囊提供一个动态的波纹过渡。
第一步 修改showDetail为true
在HikeView中,将showDetail的默认值更改为true,然后将预览固定到画布上。 这样,当您在另一个文件中处理动画时,就可以在上下文中看到图形。
第二步 在HikeGraph.swift中,定义一个新的波纹动画,并将其应用于每个生成的图形胶囊。
extension Animation { static func ripple() -> Animation { Animation.default }}
第三步 将动画切换到弹簧动画,减少阻尼分数以使钢筋跳跃。
通过在实时预览中切换仰角、心率和速度,可以看到动画的效果。
extension Animation {
static func ripple() -> Animation {
Animation.spring(dampingFraction: 0.5)
}
}
第四步 将动画加速一点,以缩短每个条移动到其新位置所需的时间。
第五步 根据位置添加延迟
extension Animation {
static func ripple(index: Int) -> Animation {
Animation.spring(dampingFraction: 0.5)
.speed(2)
.delay(0.03 * Double(index))
}
}
第六步 观察效果
观察自定义动画在图形之间转换时如何提供波纹效果。
在继续下一个教程之前,请确保取消固定预览,即showDetail改为false