为什么不自定义SwiftUI视图在ViewModel状态更改时设置动画?

时间:2020-08-12 00:07:58

标签: ios swiftui

当我的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>

1 个答案:

答案 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,它仅在MainViewZStack和{{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

应该可以正常工作。