当我的viewModel更改为错误状态时,我正在呈现一个自定义视图。我想制作此演示文稿的动画。我用枚举表示viewModel状态
enum ViewModelState<T> {
case idle
case error(Error)
case loading
case data(T)
var isError: Bool {
switch self {
case .error:
return true
default:
return false
}
}
}
在我的viewModel中,我具有此属性...
@Published var state: ViewModelState = .idle
当它更改为错误状态时,我想在错误视图中设置动画。当我在视图中使用if语句执行以下操作时,该动画会在...中显示
private var content: some View {
return ZStack {
mainView // VStack
if case let .error(error) = viewModel.state {
ErrorView(
errorDescription: error.localizedDescription,
state: $viewModel.state
)
}
}.animation(.default)
}
var body: some View {
content
.navigationBarTitle(viewModel.title)
.navigationBarBackButtonHidden(true)
}
但是我想打开错误并执行此操作
private var content: some View {
switch viewModel.state {
case .idle:
return mainView.eraseToAnyView()
case let .error(error):
return ZStack {
mainView
ErrorView(
errorDescription: error.localizedDescription,
state: $viewModel.state
)
}.animation(.default).eraseToAnyView()
default:
return EmptyView().eraseToAnyView()
}
}
我不明白为什么这种方法不能进行动画处理-有没有一种方法可以对视图进行动画处理而无需借助我的视图模型中的多个属性来表示状态枚举的状态/计算属性,或者这是最好的方法吗? / p>
答案 0 :(得分:1)
AnyView
对编译器隐藏所有实现细节。这意味着SiwftUI 不能动画,因为它会尝试在编译过程中推断所有动画。
这就是为什么您应尽可能避免使用AnyView
。
如果要将body
的某些逻辑分离为计算的属性(或函数),请使用@ViewBuilder
批注。
@ViewBuilder
private var content: some View {
switch viewModel.state {
case .idle:
mainView
case let .error(error):
ZStack {
mainView
ErrorView(
errorDescription: error.localizedDescription,
state: $viewModel.state
)
}.animation(.default)
default:
EmptyView()
}
}
请注意,我删除了媒体资源中的return
。通过将所有内容包装在@ViewBuilder
中,body
的行为与默认Group
属性非常相似。
第二个问题是动画之间的状态。
通过使用switch
,您将创建一个SwiftUI._ConditionalContent<MainView,SwiftUI.ZStack<SwiftUI.TupleView<(MainView, ErrorView)>>
这很难解析,但是您创建了一个ConditionalContent
,它仅在MainView
和ZStack
和{{1 }},这不是我们想要的。
我们应该尝试创建一个MainView
,并且不包含ErrorView
和一个可选的ZStack
。
我想通过具有计算的MainView
属性的视图模型进行扩展。
ErrorView
现在,您可以使用error: Error?
类型的extension ViewModel {
var error: Error? {
guard case let .error(error) = state else {
return nil
}
return error
}
}
函数来创建可选视图
map
应该可以正常工作。