Animation — transition

什么是 transition #

SwiftUI 中,transition 是一个视图修饰符,用于定义视图在进入或退出布局时的动画效果。通过 transition,你可以为视图的出现(Appear)和消失(Disappear)设置一些平滑过渡。

关键特点 #

  • transition 本质上是一种与视图生命周期(显示/隐藏)绑定的动画。
  • 它为视图的进入(插入)和退出(删除)提供了动态效果。
  • 常见的过渡效果包括淡入淡出移动缩放、或者自定义效果

1. 基本用法 #

显示和隐藏视图 #

你需要结合 @Statetransition 配合使用,并用 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)

当视图显示或隐藏时,透明度会平滑地从 01 或从 10


(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)更关注的是「进入/退出」时的效果。而动画更关注的是「整个视图变化过程」。你可以同时结合 transitionanimation 为视图带来更复杂的动态行为。

示例:结合动画和过渡 #

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. 注意事项 #

  1. 只适用于插入/移除的视图:

    • transition 只作用于通过 条件语句(如 if)或 .onAppear/.onDisappear 动态插入的视图。
    • 如果视图一直存在,并只改变其属性值(不插入/移除),使用 animation 而不是 transition
  2. 过渡范围的限制:

    • 过渡动画仅影响从视图「插入或删除」时的行为,而不会影响现有视图的布局调整或样式变化。
  3. 添加容器视图以避免冲突:

    • 如果给多层嵌套的视图同时应用过渡,可能会有不必要的动画冲突。为每个动画的子视图包裹特定容器是个好方法。

7. 总结 #

  • transition 是一个用来定义视图插入或移除时动画过渡的修饰符。
  • 提供了多种内置效果(opacity, slide, move(edge:), scale 等),也支持自定义效果。
  • 搭配 withAnimationif 可视化内容切换
  • 注意在正确的场景下使用 transition,如视图的动态显示或隐藏,否则需要用 animation
本文共 1809 字,创建于 Mar 15, 2025
相关标签: Xcode, SwiftUI