How to get SwiftUI Picker in subview working? (Greyed out)

守給你的承諾、 提交于 2021-01-29 21:31:02

问题


I'm working on a SwiftUI project and am having trouble getting a picker to work correctly.

I've got a hierarchy of views split into multiple files with the initial view wrapping everything in a NavigationView.

Looks something like this:

MainFile (TabView -> NavigationView)
- ListPage (NavigationLink)
-- DetailHostPage (Group.EditButton)
if editing
--- DetailViewPage
else
--- DetailEditPage (picker in a form)

The picker that I have in the DetailEditPage does not let me change it's value, though it does display the correct current value.

Picker(selection: self.$_myObj.SelectedEnum, label: Text("Type")) {
    ForEach(MyEnum.allCases, id: \.self) {
        Text("\(String(describing: $0))")
    }
}

If I wrap the picker in a navigation view directly then it works, but now I have a nested navigation view resulting in two back buttons, which is not what I want.

What is causing the picker not to allow it's selection to change, and how can I get it working?

EDIT

Here's an example of how to replicate this:

ContentView.swift

class MyObject: ObservableObject {
    @Published var enumValue: MyEnum

    init(enumValue: MyEnum) {
        self.enumValue = enumValue
    }
}

enum MyEnum: CaseIterable {
    case a, b, c, d
}

struct ContentView: View {
    @State private var objectList = [MyObject(enumValue: .a), MyObject(enumValue: .b)]

    var body: some View {
        NavigationView {
            List {
                ForEach(0..<objectList.count) { index in
                    NavigationLink(destination: Subview(myObject: self.$objectList[index])) {
                        Text("Object \(String(index))")
                    }
                }
            }
        }
    }
}

struct Subview: View {
    @Environment(\.editMode) var mode
    @Binding var myObject: MyObject

    var body: some View {
        HStack {
            if mode?.wrappedValue == .inactive {
                //The picker in this view shows
                SubViewShow(myObject: self.$myObject)
            } else {
                //The picker in this view does not
                SubViewEdit(myObject: self.$myObject)
            }
        }.navigationBarItems(trailing: EditButton())
    }
}

struct SubViewShow: View {
    @Binding var myObject: MyObject

    var body: some View {
        Form {
            Picker(selection: self.$myObject.enumValue, label: Text("enum values viewing")) {
                ForEach(MyEnum.allCases, id: \.self) {
                    Text("\(String(describing: $0))")
                }
            }
        }
    }
}

struct SubViewEdit: View {
    @Binding var myObject: MyObject
    var body: some View {
        Form {
            Picker(selection: self.$myObject.enumValue, label: Text("enum values editing")) {
                ForEach(MyEnum.allCases, id: \.self) {
                    Text("\(String(describing: $0))")
                }
            }
        }
    }
}
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}


回答1:


We don't have an idea about your enum and model (_myObj) implementation.

In the next snippet is working code (copy - paste - test it) where you can see how to implement picker with enum. You can even uncomment the lines where Form is declared, if you like to have your Picker in Form

import SwiftUI

struct Subview: View {
    @Binding var flag: Bool
    @Binding var sel: Int
    var body: some View {
        VStack {
            Text(String(describing: MyEnum.allCases()[sel]))
            Button(action: {
                self.flag.toggle()
            }) {
                Text("toggle")
            }
            if flag {
                FlagOnView()
            } else {
                FlagOffView(sel: $sel)
            }
        }
    }
}

enum MyEnum {
    case a, b, c, d
    static func allCases()->[MyEnum] {
        [MyEnum.a, MyEnum.b, MyEnum.c, MyEnum.d]
    }
}
struct FlagOnView: View {
    var body: some View {
        Text("flag on")
    }
}
struct FlagOffView: View {
    @Binding var sel: Int
    var body: some View {
        //Form {
            Picker(selection: $sel, label: Text("select")) {
                ForEach(0 ..< MyEnum.allCases().count) { (i) in
                    Text(String(describing:  MyEnum.allCases()[i])).tag(i)
                }
            }.pickerStyle(WheelPickerStyle())
        //}
    }
}

struct ContentView: View {
    @State var sel: Int = 0
    @State var flag = false
    var body: some View {
        NavigationView {
            List {
                NavigationLink(destination: Subview(flag: $flag, sel: $sel)) {
                    Text("push to subview")
                }
                NavigationLink(destination: Text("S")) {
                    Text("S")
                }
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

UPDATE change your code

struct SubViewShow: View {
    @Binding var myObject: MyObject
    @State var sel = Set<Int>()
    var body: some View {
        Form {
            List(selection: $sel) {
                ForEach(MyEnum.allCases, id: \.self) {
                    Text("\(String(describing: $0))")
                }.onDelete { (idxs) in
                    print("delete", idxs)
                }
            }
            Picker(selection: self.$myObject.enumValue, label: Text("enum values viewing")) {
                ForEach(MyEnum.allCases, id: \.self) {
                    Text("\(String(describing: $0))")
                }
            }.pickerStyle(SegmentedPickerStyle())
        }
    }
}

struct SubViewEdit: View {
    @Binding var myObject: MyObject
    @State var sel = Set<Int>()
    var body: some View {
        Form {
            List(selection: $sel) {
                ForEach(MyEnum.allCases, id: \.self) {
                    Text("\(String(describing: $0))")
                }.onDelete { (idxs) in
                    print("delete", idxs)
                }
            }
            Picker(selection: self.$myObject.enumValue, label: Text("enum values editing")) {
                ForEach(MyEnum.allCases, id: \.self) {
                    Text("\(String(describing: $0))")
                }
            }
            .pickerStyle(SegmentedPickerStyle())
        }
    }
}

and see what happens

I think, you just misunderstood what the editing mode is for.



来源:https://stackoverflow.com/questions/60590266/how-to-get-swiftui-picker-in-subview-working-greyed-out

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!