结合使用 EnvironmentObject 与 withAnimation
了解如何使用 @State 和 EnvironmentObject 相结合的方式,在复杂的视图结构中轻松管理动画。
使用 EnvironmentObject(环境变量),可以更加简洁、高效的方式来管理全局状态,使得在复杂的视图层次结构中共享和更新状态变得更加容易。我们在之前的文章中介绍过环境变量的使用方法:

使用 .transition 和 .contentTransition 可以为应用添加平滑的过渡动画,提升用户体验。但这两者都需要与 withAnimation 函数配合使用才能正确触发动画效果。
由于我们可能在多个组件中更改环境变量,在每个地方都手动使用 withAnimation 进行包装会显得繁琐且容易出错。那么,如何让 withAnimation 与环境变量更方便地结合使用呢?
接下来,我将介绍两种我常用的解决方案,以简化这种操作。
使用 @State 变量进行过渡
在视图组件中,我们可以创建一个私有的 @State 变量,并在它每次更新时,将其同步到环境变量中,并使用 withAnimation 包装这个过程,从而实现动画过渡。
假设我们有如下的环境变量:
import SwiftUI
class AppState: ObservableObject {
@Published var selectedDate: Date
init() {
// 初始化时设置为当天的日期
self.selectedDate = Date()
}
}在需要使用 AppState.selectedDate 的视图组件中,我们创建一个私有的 @State 变量,并遵循以下原则:
- 更新值:需要更新
AppState.selectedDate的地方,使用selectedDate状态变量来代替。 - 获取值:需要获取
AppState.selectedDate的地方,继续使用环境对象中的AppState.selectedDate。 - 监听变化:使用
onChange来监听selectedDate的变化,并在每次变化时,使用withAnimation将新值更新到appState.selectedDate。最后使用 onChange 来监听 selecteDate 的变化,并在每次变化时,使用 withAnimation 更新到 appState.selectedDate 中。
使用方法就像这样:
struct HomeView: View {
@EnvironmentObject var appState: AppState // 使用环境对象
@State private var selectedDate = Date
{
<省略部分代码>
DatePicker(
"选择日期",
selection: $selectedDate,
displayedComponents: [.date]
)
}
.onChange(of: selectedDate) {
withAnimaton {
appState.selectedDate = selectedDate
}
}
}在上面的代码中,我们使用 @State 变量 selectedDate 来管理本地的日期选择。onChange 监听到状态变化后,通过 withAnimation 将新的日期同步到环境对象 appState.selectedDate,从而触发动画效果。
在我的实践中,它是有效的,并能够正常触发过渡动画。
在 ObservableObject 中使用 setter 更新变量
如果你希望在 AppState 中集中管理动画,并避免在视图中创建额外的变量,可以将 selectedDate 修改为一个计算属性,并通过自定义的 setter 添加 withAnimation。
你可以像下面这样修改 AppState:
class AppState: ObservableObject {
@Published private var _selectedDate: Date
var selectedDate: Date {
get { _selectedDate }
set {
withAnimation {
_selectedDate = newValue
}
}
}
init() {
self._selectedDate = Date()
}
}在这个例子中,selectedDate 是一个计算属性,setter 中使用了 withAnimation。这样,无论你在何处更新 AppState.selectedDate,都会自动触发动画。

Comments ()