SwiftUI:具有不同ToolbarItem放置的视图会导致应用崩溃

时间:2020-11-04 22:28:54

标签: swiftui

使用具有不同ToolbarItem放置的视图时,应用程序崩溃。下面是一个代码段,可让您重现崩溃。

行为

我使用3个视图,每个视图都有自己定义的工具栏。 homeViewprofileView具有相同的工具栏结构。他们每个人都使用ToolbarItem,其位置为.bottomBar。另一方面,addView在工具栏上的动作`.cancellationAction'上有一个ToolbarItem。

按下ToolbarItem时,将更改ViewModel中的viewState。这会导致当前显示的视图发生更改。

错误消息:

[error] precondition failure: invalid attribute id: 70981 AttributeGraph precondition failure: invalid attribute id: 70981.

目标

iPhone X 14.0(18A373)

代码段:

import SwiftUI

struct SomeView: View {
    @ObservedObject var viewModel = ViewModel()
    
    var body: some View {
        NavigationView() {
            content
        }
    }
    
    private var content: AnyView {
        switch(viewModel.viewState) {
        case .home: return AnyView(homeView());
        case .add: return AnyView(addView());
        case .profile: return AnyView(profileView());
        }
    }
    
    func homeView() -> some View {
        Text("Home View")
            .toolbar {
                ToolbarItem(placement: .bottomBar) {
                    HStack {
                        Button("Home", action: { viewModel.setViewState(state: .home) })
                        Button("Add", action: { viewModel.setViewState(state: .add) })
                        Button("Profile", action: { viewModel.setViewState(state: .profile) })
                    }
                }
            }
    }
    
    func addView() -> some View {
        Text("Add View")
            .toolbar {
                ToolbarItem(placement: .cancellationAction) {
                    Button("Cancel", action: { viewModel.setViewState(state: .home)})
                }
            }
    }
    
    func profileView() -> some View {
        Text("Profile View")
            .toolbar {
                ToolbarItem(placement: .bottomBar) {
                    HStack {
                        Button("Home", action: { viewModel.setViewState(state: .home) })
                        Button("Add", action: { viewModel.setViewState(state: .add) })
                        Button("Profile", action: { viewModel.setViewState(state: .profile) })
                    }
                }
            }
    }
}

// MARK: View Model

extension SomeView {
    class ViewModel: ObservableObject {
        @Published var viewState: ViewState
        
        enum ViewState {
            case home, add, profile
        }
        
        init() {
            self.viewState = .home
        }
        
        func setViewState(state: ViewState) {
            self.viewState = state;
        }
    }
}

// MARK: Preview

struct SomeView_Previews: PreviewProvider {
    static var previews: some View {
        SomeView()
    }
}

1 个答案:

答案 0 :(得分:1)

是的,对我来说似乎是个错误。

可能的解决方法是将每个视图放在单独的NavigationView中:

struct ContentView: View {
    @ObservedObject var viewModel = ViewModel()

    var body: some View {
        content
    }

    @ViewBuilder
    var content: some View {
        switch viewModel.viewState {
        case .home: NavigationView { homeView() }
        case .add: NavigationView { addView() }
        case .profile: NavigationView { profileView() }
        }
    }

    ...
}

或者,您可以将bottomBar添加到addView

func addView() -> some View {
    Text("Add View")
        .toolbar {
            ToolbarItem(placement: .cancellationAction) {
                Button("Cancel", action: { viewModel.setViewState(state: .profile) })
            }
            ToolbarItem(placement: .bottomBar) {
                Text("")
            }
        }
}

或仅将addView显示为sheet