Reputation: 1499
In my app, I need to use a Picker
in two different places. In one place, it's to set a property to one of three values: A, B, or C. But, in another place, I want to use the picker to filter a array of items to show either all items (no filter) or only the A, B, or C items.
So, my first attempt was to create an enum
like so:
enum Category {
case all
case A
case B
case C
}
Using this, I can filter my list successfully. But, when I try to create a new item in the array, I don't want all
to be an option. The user should only see a picker with A, B, and C.
I could try:
enum Category {
case A
case B
case C
}
but then how do I add the all
option for the filter picker?
(To address some comments below, here are some more details on the specific thing I'm try to accomplish...
A tournament can be a men's, women's, or mixed tournament. On the screen where I list the tournaments, I want to be able to show all tournaments or just the men's, just the women's or just the mixed tournaments. So, I have a picker that spans the width of the iPhone. Looks and works great.
Obviously, when adding a new item to the list, I have to specify its category, but not "all". Also a picker.
So, in one case, I need three values, in the other case, I need the same three values with "All" added at the beginning.)
Upvotes: 3
Views: 2748
Reputation: 385650
You should define your enum
without the all
case, because all
is not a valid Category
for an item. (This is a programming guideline known as “make illegal states unrepresentable”.)
enum Category: Hashable, CaseIterable {
case a
case b
case c
}
With that definition, the Picker
for setting an item's property can look like this:
Picker("Category", selection: $category) {
ForEach(Category.allCases, id: \.self) { category in
Text(verbatim: "\(category)")
.tag(category)
}
}
Then you should recognize that your filter is optional. You can filter by item category, or you can perform no filtering. So your filter property should be declared optional:
@Binding var categoryFilter: Category?
The Picker
for setting the filter then needs to be careful to use optional tags:
Picker("Category Filter", selection: $categoryFilter) {
Text("None")
.tag(Category?.none)
ForEach(Category.allCases, id: \.self) { category in
Text(verbatim: "\(category)")
.tag(Category?.some(category))
}
}
Upvotes: 7
Reputation: 313
To answer your question if I understood you correctly.
Modify your enum to implement the CaseIterable take a look at it below.
enum Category:CaseIterable{
case all
case A
case B
case C
}
Filter out where your category matches the all case. Example below.
let preferredcategory = Category.allCases.filter{ return $0 != Category.all}
To test our result see the code below.
print(preferredcategory.count)
for catname in preferredcategory {
print("Hello, \(catname)!")
}
You can read more on this respective pages.
https://developer.apple.com/documentation/swift/caseiterable
https://developer.apple.com/documentation/swift/caseiterable/2994869-allcases
Thanks.
So you can use the preferredCategory variable to show the user your category for the one you do not want all to show. you can also use the same filter to show only the part of the enum that has all case as well.
Also, the good thing is you get to keep your enum and reuse it everywhere in your application without having to hardcode values. if you want to show only All you just have to filter out the remaining case.
Some people may want to downvote without a valid reasons but if you believe the approach is wrong feel free to edit or leave a comment on how to improve the solution.
Upvotes: 0
Reputation: 2671
You can make your enum CaseIterable
and then you can use the allCases
property when you want to display all enum values, and use a filter
when you only want certain cases displayed.
NOTE: In my sample code, you'll need to replace selection: .constant(Category.a)
with an @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({ $0 != .all }), id: \.self) { category in
Text(category.rawValue).tag(category)
}
}
}
}
}
}
Upvotes: 1
Reputation: 214
You can create enum in this way
enum Category {
case all
case A
case B
case C
static let categories: [Category] = [.A, .B, .C]
}
And then use the categories array when you need to choose among three.
Upvotes: 2