SwiftUI - 为不同的选择器使用除了一个枚举值之外的所有值

SwiftUI - using all but one values of Enum for different Pickers

在我的应用程序中,我需要在两个不同的地方使用 Picker。在一个地方,它是将 属性 设置为三个值之一:A、B 或 C。但是,在另一个地方,我想使用选择器来过滤一组项目以显示所有项目(无过滤器)或仅 A、B 或 C 项。

所以,我的第一次尝试是创建一个 enum 像这样:

enum Category {
  case all
  case A
  case B
  case C
}

使用它,我可以成功过滤我的列表。但是,当我尝试在数组中创建一个新项目时,我不希望 all 成为一个选项。用户应该只会看到带有 A、B 和 C 的选择器。

我可以试试:

enum Category {
  case A
  case B
  case C
}

但是我如何添加过滤器选择器的all选项?

(为了解决下面的一些评论,这里有一些关于我试图完成的具体事情的更多细节...

锦标赛可以是男子、女子或混合锦标赛。在我列出锦标赛的屏幕上,我希望能够显示 所有 锦标赛或仅男子锦标赛、女子锦标赛或混合锦标赛。所以,我有一个跨越 iPhone 宽度的选择器。看起来很棒。

显然,在向列表中添加新项目时,我必须指定其类别,而不是“全部”。也是一个拾取器。

所以,在一种情况下,我需要三个值,在另一种情况下,我需要在开头添加“全部”的相同三个值。)

你可以让你的枚举 CaseIterable 然后当你想显示所有枚举值时你可以使用 allCases 属性 ,当你想要显示所有枚举值时使用 filter只希望显示某些情况。

注意: 在我的示例代码中,您需要将 selection: .constant(Category.a) 替换为 @Binding

struct Test {
    enum Category: String, CaseIterable {
        case all = "All"
        case a = "A"
        case b = "B"
        case c = "C"
    }
    
    struct TestView: View {
        var body: some View {
            VStack {
                Picker("Picker Title", selection: .constant(Category.a)) {
                    ForEach(Category.allCases, id: \.self) { category in
                        Text(category.rawValue).tag(category)
                    }
                }
                
                Picker("Picker Title", selection: .constant(Category.a)) {
                    ForEach(Category.allCases.filter({ [=10=] != .all }), id: \.self) { category in
                        Text(category.rawValue).tag(category)
                    }
                }
            }
        }
    }
}

您可以通过这种方式创建枚举

enum Category {
    case all
    case A
    case B
    case C
    
    static let categories: [Category] = [.A, .B, .C]
}

然后当您需要在三个中进行选择时使用类别数组。

您应该在没有 all 大小写的情况下定义 enum,因为 all 不是有效的 Category 项目。 (这是一个称为“make illegal states unrepresentable”的编程指南。)

enum Category: Hashable, CaseIterable {
    case a
    case b
    case c
}

根据该定义,用于设置项目 属性 的 Picker 可以如下所示:

Picker("Category", selection: $category) {
    ForEach(Category.allCases, id: \.self) { category in
        Text(verbatim: "\(category)")
            .tag(category)
    }
}

那么您应该认识到您的过滤器是可选的。您可以按项目类别过滤,也可以不执行过滤。所以你的过滤器 属性 应该声明为可选的:

@Binding var categoryFilter: Category?

然后设置过滤器的Picker需要注意使用可选标签:

Picker("Category Filter", selection: $categoryFilter) {
    Text("None")
        .tag(Category?.none)
    ForEach(Category.allCases, id: \.self) { category in
        Text(verbatim: "\(category)")
            .tag(Category?.some(category))
    }
}

如果我理解正确,请回答你的问题。

  1. 修改您的枚举以实现 CaseIterable,请看下面。

     enum Category:CaseIterable{
      case all
      case A
      case B   
      case C
     }
    
  2. 过滤出您的类别与所有大小写匹配的地方。示例如下。

    let preferredcategory = Category.allCases.filter{ return [=11=] !=  Category.all}
    
  3. 要测试我们的结果,请参见下面的代码。

     print(preferredcategory.count)
     for catname in preferredcategory {
     print("Hello, \(catname)!")
    }
    
  4. 您可以在相应的页面上阅读更多内容。

https://developer.apple.com/documentation/swift/caseiterable

https://developer.apple.com/documentation/swift/caseiterable/2994869-allcases

https://www.hackingwithswift.com/example-code/language/how-to-list-all-cases-in-an-enum-using-caseiterable

谢谢。

因此您可以使用 preferredCategory 变量向用户显示您不想全部显示的类别。您还可以使用相同的过滤器来仅显示枚举中包含所有大小写的部分。

此外,好处是您可以保留您的枚举并在您的应用程序的任何地方重复使用它,而不必对值进行硬编码。如果你只想显示所有你只需要过滤掉剩下的情况。

有些人可能想在没有正当理由的情况下投反对票,但如果您认为这种方法是错误的,请随时编辑或就如何改进解决方案发表评论。