如何让 SwiftUI Picker 在子视图中工作? (变灰)

Posted

技术标签:

【中文标题】如何让 SwiftUI Picker 在子视图中工作? (变灰)【英文标题】:How to get SwiftUI Picker in subview working? (Greyed out) 【发布时间】:2020-03-08 17:39:27 【问题描述】:

我正在处理一个 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))")
    

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

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

编辑

这是一个如何复制的示例:

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


【问题讨论】:

我试图毫无困难地模仿相同的层次结构......向我们展示你的模型和枚举。你在哪里嵌套导航视图?从提供的信息来看,有任何 @user3441734 我接受了您的回答并对其进行了修改,以说明我是如何解决问题的。我不确定它是否与 EditButton 和 Group 有关,因为这些是我的设置和你的设置之间的主要区别。 发现如果我使用 EditButton() 显示细节或编辑子视图,细节子视图选择器工作正常,但编辑视图选择器不行。 我现在明白了,你在说什么。你喜欢在那里编辑什么?选择器被禁用,只是因为它不可编辑。你对那里有什么期望? change (add) .pickerStyle(SegmentedPickerStyle()) 你会看到,选择器工作,只是在编辑模式下,你不能改变视图层次结构。这是标准行为,不是吗? 【参考方案1】:

我们对您的枚举和模型 (_myObj) 实施一无所知。

在下一个 sn-p 是工作代码(复制 - 粘贴 - 测试它),您可以在其中看到如何使用枚举实现选择器。如果您希望在 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())
        
    

看看会发生什么

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

【讨论】:

感谢您在这方面的持续帮助。我知道编辑模式可以用于列表,但是在苹果官方教程Working with UI Controls 他们使用 EditButton 的方式与我的示例完全相同。向下滚动到第 2 节和第 3 节以查看示例。 刚刚看到您对我的主要帖子的评论。我不知道编辑模式如何影响视图层次结构。如果它的目的是阻止导航直到编辑完成,那么我想我会听从你的建议并自己处理“编辑模式”并使用官方的列表编辑模式。

以上是关于如何让 SwiftUI Picker 在子视图中工作? (变灰)的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI:如何根据 Picker 的值更新 ForEach 循环的范围

如何在没有额外空间的情况下更改 SwiftUI Picker 视图大小?

SwiftUI 从另一个视图中捕获 Picker 值

SwiftUI 如何让 ForEach 循环根据 Picker 中选定月份的天数进行迭代

更新 SwiftUI 导航栏标题

为 SwiftUI 寻找一个简单的自定义视图:picker