什么是 transition?#
在 SwiftUI 中,transition 是一个视图修饰符,用于定义视图在进入或退出布局时的动画效果。通过 transition,你可以为视图的出现(Appear)和消失(Disappear)设置一些平滑过渡。
关键特点#
transition本质上是一种与视图生命周期(显示/隐藏)绑定的动画。- 它为视图的进入(插入)和退出(删除)提供了动态效果。
- 常见的过渡效果包括淡入淡出、移动、缩放、或者自定义效果。
1. 基本用法#
显示和隐藏视图#
你需要结合 @State 和 transition 配合使用,并用 withAnimation 为过渡增加动画效果。
示例:淡入淡出过渡
import SwiftUI
struct ContentView: View {
@State private var isVisible = false // 控制视图显示和隐藏
var body: some View {
VStack {
Button("Toggle View") {
withAnimation { // 添加动画
isVisible.toggle()
}
}
if isVisible {
Text("Hello, World!")
.padding()
.background(Color.blue)
.cornerRadius(10)
.transition(.opacity) // 使用透明度过渡
}
}
}
}效果:
- 点击按钮时:通过透明度的渐变效果(
opacity),视图会平滑显现或消失,而不是瞬间改变。
2. 内置过渡效果#
(1) 常见的过渡类型#
SwiftUI 提供了多种内置的过渡效果,包括:
| 过渡类型 | 描述 |
|---|---|
.opacity | 透明度渐变,视图通过淡入淡出的透明度动画显示或隐藏。 |
.scale | 缩放过渡,视图通过从小到大或从大到小的缩放动画显示或隐藏。 |
.slide | 滑动过渡,视图从屏幕边缘滑动进入或退出。 |
.move(edge:) | 从某个边缘移动进入或退出(设置边缘参数,如 .leading、.trailing、.top、.bottom)。 |
.offset() | 偏移过渡,视图从指定位置渐渐移动到最终位置,或者离开位置时偏移。 |
.asymmetric() | 定义不同的进入(插入效果)和退出(删除效果)的过渡。 |
(2) 使用 opacity 渐变:#
.transition(.opacity)当视图显示或隐藏时,透明度会平滑地从 0 到 1 或从 1 到 0。
(3) 使用 scale 缩放:#
.transition(.scale)当视图显示或隐藏时,视图会从 0x0 缩放到原始大小,或者从原始大小缩小到 0x0。
(4) 使用 slide 滑动:#
.transition(.slide)当视图出现时,它会从屏幕边缘滑动到视图内;当消失时,它会滑出屏幕。
示例:滑动过渡效果
if isVisible {
Text("Hello, SwiftUI!")
.transition(.slide) // 使用 slide 过渡
}(5) 使用 move(edge:):#
.transition(.move(edge: .leading))- 当视图插入时,从指定边缘(如
.leading左边缘)移动到当前布局位置。 - 当视图被移除时,从当前布局位置移到指定边缘。
示例:从顶部移动进入
if isVisible {
Rectangle()
.fill(Color.red)
.frame(width: 200, height: 100)
.transition(.move(edge: .top)) // 从顶部进入或退出
}(6) 组合效果:#
当你想将多个过渡效果组合在一起时,可以使用 .combined(_: Transition)。
示例:透明度 + 移动组合
.transition(.opacity.combined(with: .move(edge: .bottom)))- 视图在出现时从底部移动并逐渐显现;
- 视图在消失时透明度降低,并且移回底部。
3. 非对称过渡#
什么是非对称过渡?#
非对称过渡意味着:视图进入时的过渡效果和视图退出时的过渡效果不一样。
使用 .asymmetric(insert:remove:):
insert参数定义视图插入时的效果。remove参数定义视图移除时的效果。
示例:非对称移动和透明化过渡
.transition(.asymmetric(insert: .move(edge: .trailing), // 从右侧进入
remove: .opacity)) // 通过透明化消失完整示例代码:
struct ContentView: View {
@State private var isVisible = false
var body: some View {
VStack {
Button("Toggle View") {
withAnimation {
isVisible.toggle()
}
}
if isVisible {
Text("Non-symmetric Transition")
.padding()
.background(Color.orange)
.cornerRadius(10)
.transition(.asymmetric(insert: .slide, remove: .opacity))
}
}
}
}4. 自定义过渡#
如何自定义过渡?#
可以通过 .modifier 定义自定义的插入(进入)和移除(退出)效果。
示例:旋转过渡
import SwiftUI
struct RotateTransition: ViewModifier {
let rotation: Double
func body(content: Content) -> some View {
content
.rotationEffect(.degrees(rotation)) // 应用旋转效果
.opacity(rotation == 0 ? 1 : 0) // 控制透明度,消失时透明度为 0
}
}
extension AnyTransition {
static var rotate: AnyTransition {
AnyTransition.modifier(
active: RotateTransition(rotation: 90), // 退出时的效果
identity: RotateTransition(rotation: 0) // 初始情况下(静止时)的效果
)
}
}
struct ContentView: View {
@State private var isVisible = false
var body: some View {
VStack {
Button("Toggle Rotation") {
withAnimation {
isVisible.toggle()
}
}
if isVisible {
Text("Rotated Text")
.font(.title)
.padding()
.background(Color.green)
.cornerRadius(10)
.transition(.rotate) // 使用自定义旋转过渡
}
}
.padding()
}
}效果:
- 视图出现时会有旋转效果。
- 视图消失时旋转退出并逐渐消失。
5. 添加进入和退出动画#
过渡(transition)更关注的是「进入/退出」时的效果。而动画更关注的是「整个视图变化过程」。你可以同时结合 transition 和 animation 为视图带来更复杂的动态行为。
示例:结合动画和过渡#
import SwiftUI
struct ContentView: View {
@State private var isVisible = false
var body: some View {
VStack {
Button("Toggle View") {
withAnimation(.easeInOut(duration: 0.5)) {
isVisible.toggle()
}
}
if isVisible {
RoundedRectangle(cornerRadius: 20)
.fill(Color.blue)
.frame(width: 200, height: 100)
.transition(.scale) // 使用缩放动画过渡
}
}
}
}6. 注意事项#
只适用于插入/移除的视图:
transition只作用于通过 条件语句(如if)或.onAppear/.onDisappear动态插入的视图。- 如果视图一直存在,并只改变其属性值(不插入/移除),使用
animation而不是transition。
过渡范围的限制:
- 过渡动画仅影响从视图「插入或删除」时的行为,而不会影响现有视图的布局调整或样式变化。
添加容器视图以避免冲突:
- 如果给多层嵌套的视图同时应用过渡,可能会有不必要的动画冲突。为每个动画的子视图包裹特定容器是个好方法。
7. 总结#
transition是一个用来定义视图插入或移除时动画过渡的修饰符。- 提供了多种内置效果(
opacity,slide,move(edge:),scale等),也支持自定义效果。 - 搭配
withAnimation和if可视化内容切换。 - 注意在正确的场景下使用
transition,如视图的动态显示或隐藏,否则需要用animation。