首页 > 解决方案 > 如何让 SwiftUI Picker 在子视图中工作?(变灰)

问题描述

我正在开发一个 SwiftUI 项目,但无法让选择器正常工作。

我将视图层次结构拆分为多个文件,初始视图将所有内容包装在 NavigationView 中。

看起来像这样:

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

我拥有的选择器DetailEditPage不允许我更改它的值,尽管它确实显示了正确的当前值。

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

如果我直接将选择器包装在导航视图中,那么它可以工作,但现在我有一个嵌套导航视图,导致两个后退按钮,这不是我想要的。

是什么导致选择器不允许它的选择改变,我怎样才能让它工作?

编辑

以下是如何复制此内容的示例:

内容视图.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()
    }
}

标签: swiftswiftuiswiftui-picker

解决方案


我们不知道您的枚举和模型 (_myObj) 实现。

在下一个片段中是工作代码(复制 - 粘贴 - 测试它),您可以在其中看到如何使用枚举实现选择器。如果您希望在 Form 中使用 Picker,您甚至可以取消注释 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()
    }
}

更新更改您的代码

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())
        }
    }
}

看看会发生什么

我想,你只是误解了编辑模式的用途。

在此处输入图像描述


推荐阅读