Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI - does ForEach have a endIndex or lastindex?

Tags:

swift

swiftui

I'm using ForEach to create a loop. However, I want to render a Rectangle conditionally depending upon the count of the loop. For example, don't render the rectangle if the last loop iteration.

What's the correct syntax for this?

I'm looking for something like this (non working pseudo-code)

ForEach(arrayOfThings, id: \.title) { thing in
    // Stuff that happens on every iteration of loop

    // Conditional section
    if (thing.endIndex-1) {
        Rectangle()
        .frame(width: 100, height: 1, alignment: .bottom)
        .foregroundColor(Color("666666"))
    }
}

I am aware there are things like for (offset, element) in array.enumerated() { } but you can't use them in views. I wondered if there is a convenience feature in ForEach to solve this need?

Currently I am doing this to workaround:

ForEach(0..<arrayOfThings.count) { i in
    // Stuff that happens on every iteration of loop

    // Conditional section
    if (i = self.arrayOfThings.count-1) {
        Rectangle()
        .frame(width: 100, height: 1, alignment: .bottom)
        .foregroundColor(Color("666666"))
    }
}
like image 442
Ben Frain Avatar asked Oct 15 '19 12:10

Ben Frain


People also ask

How does ForEach work in SwiftUI?

ForEach in SwiftUI is a view struct in its own right, which means you can return it directly from your view body if you want. You provide it an array of items, and you may also need to tell SwiftUI how it can identify each of your items uniquely so it knows how to update them when values change.

What can ForEach loops not be used for?

It is just a variable. For-each cannot be used to initialize any array or Collection, because it loops over the current contents of the array or Collection, giving you each value one at a time. The variable in a for-each is not a proxy for an array or Collection reference.

Can you use for loops in SwiftUI?

It is not possible to use procedural looping mechanisms such as For and While loops to layout views in SwiftUI. The SwiftUI framework provides the ForEach struct to accomplish an alternative to repeatedly add views to a view.


2 Answers

If your arrayOfThings is Equatable you could do

ForEach(arrayOfThings, id: \.title) { thing in
    if thing == arrayOfThings.last {
        // do something
    }
}

Which is more readable than checking index vs count in my opinion.

like image 146
Casper Zandbergen Avatar answered Oct 12 '22 18:10

Casper Zandbergen


To know if it is the last element, you can just test if the KeyPath used as id is the same for last element and the current element.

Note that the id parameter is ensured to be unique (at runtime) and Equatable. Therefore, you cannot have any problems regarding duplicated elements or missing equality, like you could by using the element directly even if it is not used as id.

ForEach(myArray, id: \.someProperty) { element in
    if element.someProperty == myArray.last?.someProperty {
        // do something with the last element
    }
}

or in case you use an Identifiable element directly or use id: \.self:

ForEach(myArray) { element in
    if element == myArray.last {
        // do something with the last element
    }
}
like image 23
Daniel Avatar answered Oct 12 '22 18:10

Daniel