结合使用 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
,都会自动触发动画。