Reputation: 1036
I'm currently developing an application using SwiftUI
.
If I run the code below, the display result will be A
, But I want to make it the display result B
.
What kind of code can this be achieved?
Here is the code:
struct TestView:View {
let fruits = ["apple","apple","apple","orange","orange","banana"]
@State var tmpFruits = [""]
var body: some View{
List(fruits, id: \.self){fruit in
if tmpFruits.contains(fruit) == false{
Button(action: {
}, label: {
Text(fruit)
})
.onAppear(){
tmpFruits.append(fruit)
}
}
}
}
}
Swift 5.0
SwiftUI 2.0
Upvotes: 0
Views: 609
Reputation: 30391
You need to have a List
with unique and constant IDs. Currently, the ID is the string for each element in fruits
. The problem with that is since there are repeated items, you are violating the unique ID rule.
A way to solve this is filtering fruits
first, hence unique IDs. It also greatly simplifies the view code.
This uses Unique from apple/swift-algorithms for .uniqued()
. Remember to import Algorithms
.
Code:
import Algorithms
struct TestView: View {
private let fruits = ["apple", "apple", "apple", "orange", "orange", "banana"]
var body: some View {
List(Array(fruits.uniqued()), id: \.self) { fruit in
Button(fruit) {
print("action")
}
}
}
}
Upvotes: 2
Reputation: 63271
Ideally, you should use the official swift-algorithms
package to gain access to a uniqued()
function on sequences, which will do exactly what you're looking for.
If you're not using SPM or don't want to pull in that dependancy (though I really do encourage it, it's a first party Apple library, it's open source, and has really great stuff!), you can use a hand-rolled extension, like the community has been doing for years. Something like this would work for your purposes
public extension Sequence where Element: Hashable {
/// Return the sequence with all duplicates removed.
///
/// i.e. `[ 1, 2, 3, 1, 2 ].uniqued() == [ 1, 2, 3 ]`
///
/// - note: Taken from stackoverflow.com/a/46354989/3141234, as
/// per @Alexander's comment.
func uniqued() -> [Element] {
var seen = Set<Element>()
return self.filter { seen.insert($0).inserted }
}
}
Once that's in place, this is as simple as:
struct TestView: View {
private let fruits = ["apple", "apple", "apple", "orange", "orange", "banana"]
var body: some View {
List(fruits.uniqued(), id: \.self) { fruit in
Button(fruit) {
print("action")
}
}
}
}
Upvotes: 1
Reputation: 1
Try with this
List {
ForEach(fruits, id: \.self) { fruit in
if !tmpFruits.contains(fruit) {
Button(action: {
}, label: {
Text(fruit)
})
.onAppear() {
tmpFruits.append(fruit)
print(tmpFruits)
}
}
}
}
Upvotes: 0