如何让 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 视图大小?