什么是 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
。