【问题标题】:Master-Detail-View: jump between viewsMaster-Detail-View:在视图之间跳转
【发布时间】:2021-04-08 07:03:41
【问题描述】:

[缩短版]

我需要在视图之间导航方面的帮助。我已经完成了我的作业,发现这可以通过一个布尔变量来实现,该变量具有与 isActive 的读/写绑定。但它到目前为止还没有工作。

以下是代码的摘录。在顶层视图中,它显示了一个人员列表,每个人员都有一个用于编辑人员属性的导航链接。

目前我还有另外两个视图来管理列表:ClearList 和 NewPerson。我已将两者作为进一步的导航链接嵌入。

我现在想要实现的是,当 ClearList 中的按钮被按下时,视图会自动变为 NewPerson。

以下是失败的几次尝试之一。我在 AppState 中包含了布尔变量,以便从所有视图中访问它,但是当它被更改时没有任何反应。

再次感谢任何帮助!

struct Person: Identifiable, Hashable {
    let id: Int
    var name: String
}

class AppState : ObservableObject {
    @Published var activeIds : [Int] = [0,1]
    @Published var persons: [Person] = [Person(id: 0, name: "Dummy1"),
                                    Person(id: 1, name: "Dummy2"),
                                    Person(id: 2, name: "Dummy3")]
    
    @Published var newPersonViewActive: Bool = false // by setting this variable to true,
                                                     // I want to switch to the newPerson view.
                                                     // Doesn't work so far... 

    var activePersons : [Person] {
        return activeIds.compactMap { id in
            persons.first(where: { $0.id == id
            })
        }
    }
        
}

struct ContentView: View {
    @StateObject var state = AppState()
    
    var body: some View {
        TabView {
            NavigationView {
                List {
                    NavigationLink(
                        destination: ClearList(state: state)
                        label: {Text("clear list")}
                    )
                    ForEach(state.activePersons, id: \.self) { person in
                        NavigationLink(
                            destination: EditPerson(person: state.bindingForId(id: person.id)),
                            label: {
                                VStack (alignment: .leading) {
                                    Text(person.name)
                                        .font(.system(size: 26, weight: .regular))
                         
                                }.padding(15)
                            })
                    }
                    NavigationLink(
                        destination: NewPerson(state: state),
                        isActive: $state.newPersonViewActive,
                        label: {Image(systemName: "person.crop.circle.badge.plus")})
                }.environment(\.defaultMinListRowHeight, 30)
                .navigationTitle("Participants")
            }
            .tabItem{
                Image(systemName: "square.and.pencil")
                Text("Planning")
            }
        }
    }
}

struct EditPerson : View {
    
    // manage the current order of a particular person

    }
}

struct ClearList : View {
    @ObservedObject var state : AppState
    
    var body: some View {
        Button(action: {
            state.activePersonsIds = []
            state.newPersonViewActive = true // I thought this would make the
                                             // newPerson view active.
                                             // It doesn't...

    }
}

struct NewPerson: View {
    @ObservedObject var state : AppState
    var body: some View {

// add a new person
        
    }
}

【问题讨论】:

  • 您是否要求有人为您编写代码? SO 不是代码编写服务。
  • 不,我不想得到比这里任何人更多的帮助。我只需要这个 .isActive 不起作用的东西的建议。我应该以什么方式寻求帮助?我应该发布失败尝试的代码吗?我应该提供更少的背景吗?当然,我没有必要描述我的项目。您认为 SO 只提供所需的尽可能多的信息更合适吗?
  • 您应该查看How to Ask 以改进、编辑和格式化您的问题。删除所有不必要的代码,阅读 Minimal Reproducible Example 是什么当您有明确的计划时,我们可以尝试帮助您解决问题,但就目前而言,您要求为您编写所有内容,以便我们提供可接受的答案.
  • 好的,谢谢。我已经开始缩短代码。我稍后会完成。
  • 我已经缩短了代码并包含了我尝试过的许多版本中的一个,但这些版本不起作用。希望没问题。

标签: swiftui swiftui-navigationlink


【解决方案1】:

与其将清除按钮设置为 NavigationLink 以转到带有要清除的另一个按钮的页面,看起来您想要的只是有一个非 NavigationLink 按钮来清除列表并按下 NewPerson 视图:

struct ContentView: View {
    @StateObject var state = AppState()
    
    var body: some View {
        TabView {
            NavigationView {
                List {
                    Button(action: { //<-- Here
                        state.activeIds = []
                        state.newPersonViewActive = true
                    }) {
                        Text("Clear")
                    }
                    ForEach(state.activePersons, id: \.self) { person in
                        NavigationLink(
                            destination: EditPerson(person: state.bindingForId(id: person.id)),
                            label: {
                                VStack (alignment: .leading) {
                                    Text(person.name)
                                        .font(.system(size: 26, weight: .regular))
                                    
                                }.padding(15)
                            })
                    }
                    NavigationLink(
                        destination: NewPerson(state: state),
                        isActive: $state.newPersonViewActive,
                        label: {Image(systemName: "person.crop.circle.badge.plus")})
                }.environment(\.defaultMinListRowHeight, 30)
                .navigationTitle("Participants")
            }
            .tabItem{
                Image(systemName: "square.and.pencil")
                Text("Planning")
            }
        }
    }
}

struct Person: Identifiable, Hashable {
    let id: Int
    var name: String
}

class AppState : ObservableObject {
    @Published var activeIds : [Int] = [0,1]
    @Published var persons: [Person] = [Person(id: 0, name: "Dummy1"),
                                        Person(id: 1, name: "Dummy2"),
                                        Person(id: 2, name: "Dummy3")]
    
    @Published var newPersonViewActive: Bool = false
    
    var activePersons : [Person] {
        return activeIds.compactMap { id in
            persons.first(where: { $0.id == id
            })
        }
    }
    
    func bindingForId(id: Int) -> Binding<Person> {
        .init { () -> Person in
            self.persons.first(where: { $0.id == id }) ?? Person(id: -1, name: "()")
        } set: { (newValue) in
            self.persons = self.persons.map {
                if $0.id == id {
                    return newValue
                } else {
                    return $0
                }
            }
        }
        
    }
    
}

struct EditPerson : View {
    @Binding var person : Person
    
    var body: some View {
        Text("Edit")
    }
}

struct NewPerson: View {
    @ObservedObject var state : AppState
    var body: some View {
        Text("New person")
    }
}

更新,基于 cmets

我强烈建议不要这样做,因为这不是一个好的 UX 体验。请改用 Alert 或 ActionSheet 来确认操作。

struct ClearList : View {
    @ObservedObject var state : AppState
    @Environment(\.presentationMode) private var presentationMode

    var body: some View {
        Button(action: {
            state.activeIds = []
            presentationMode.wrappedValue.dismiss()
            DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
                state.newPersonViewActive = true
            }
        }) {
            Text("Clear")
        }
    }
}

【讨论】:

  • 确实,这将是最直接的解决方案。但是,我想防止用户无意中单击“清除”,而导航链接是一种方法。
  • 实现这一点的正常方法是通过AlertActionSheet 让他们确认他们的选择。
  • 我已经更新了我的答案,以包含您似乎要求的内容。不过,我建议不要使用该选项。
【解决方案2】:

我想,我找到了一个按原计划工作的解决方案:显然“onDisappear{state.newPersonViewActive = true}”(正如 lorem ipsum 所建议的,谢谢顺便说一句)可以与“.dismiss()”结合使用:


struct ClearList: View {
    @ObservedObject var state : AppState
    @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
    
    var body: some View {
        Button(action: {
            state.activeIds.removeAll()
            self.presentationMode.wrappedValue.dismiss()     //  <---       
        }) {
            Text("clear list")
        }.onDisappear{state.newPersonViewActive = true}      //  <---
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-05-30
    • 2013-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-23
    • 1970-01-01
    相关资源
    最近更新 更多