💭 @GestureState 与 @State 的区别及适用场景

为您每周带来有关 Swift 和 SwiftUI 的精选资讯!

TL;DR: @GestureState 专为手势操作设计,能在手势中断时自动重置状态,适合短暂的、与手势相关的状态管理;而 @State 更通用,但需手动处理手势中断逻辑。

背景

@GestureState 是 SwiftUI 为手势操作设计的专属状态管理工具。在许多场景下,开发者可能发现使用 @State 也能完成类似的任务,那么苹果为何额外提供 @GestureState?本文将对两者进行比较,并探讨其适用场景与核心差异。

类似的表现

@GestureState@State 都可以用于存储和更新状态,例如实现点击或拖拽等交互效果。

使用 @GestureState

以下代码展示了 @GestureState 的使用:

Swift
struct ContentView: View {
    @GestureState var isPressed = false
    var body: some View {
        Rectangle()
            .fill(.orange)
            .frame(width: 200, height: 200)
            .gesture(
                DragGesture(minimumDistance: 0)
                    .updating($isPressed) { _, state, _ in
                        state = true
                    }
            )
            .overlay(
                Text(isPressed ? "Pressing" : "")
            )
    }
}

在此例中,@GestureState 在手势活动期间被更新为 true,当手势结束或被打断时,状态会自动重置为 false

使用 @State

类似功能可以用 @State 实现:

Swift
struct ContentView: View {
    @State var isPressed = false
    var body: some View {
        Rectangle()
            .fill(.orange)
            .frame(width: 200, height: 200)
            .gesture(
                DragGesture(minimumDistance: 0)
                    .onChanged { _ in
                        isPressed = true
                    }
                    .onEnded { _ in
                        isPressed = false
                    }
            )
            .overlay(
                Text(isPressed ? "Pressing" : "")
            )
    }
}

表面上看,这两种方法在功能上几乎相同。

核心区别

手势中断的处理@GestureState@State 的关键差异所在。

手势中断场景

当手势被系统操作打断(例如下拉通知中心、启动应用切换手势但未完成等),onEnded 闭包将被忽略,导致无法执行 @State 的重置操作。而 @GestureState 会在这种情况下自动复位。

  • @GestureState 的表现: 状态会在手势中断时自动恢复到初始值,无需额外处理。
  • @State 的表现: 手势中断时,onEnded 不会被调用,状态保持手势最后的值,导致状态可能不准确。

示例对比

以下视频演示了手势中断时的行为差异:

  • @GestureState:状态在中断后自动复位。
  • @State:状态不会自动复位,需手动处理中断逻辑。

开发者也可以利用 @State 不会在手势被打断时自动复位的特性来实现一些特殊的需求。

@GestureState 功能总结

  • 专为手势设计,状态管理自动化。
  • 更适合短暂的、与手势操作相关的状态。
  • 自动处理中断和复位。
  • 更方便的设置动画。

延伸阅读