Get Index in Foreach in Swiftui

Get index in ForEach in SwiftUI

This works for me:

Using Range and Count

struct ContentView: View {
@State private var array = [1, 1, 2]

func doSomething(index: Int) {
self.array = [1, 2, 3]
}

var body: some View {
ForEach(0..<array.count) { i in
Text("\(self.array[i])")
.onTapGesture { self.doSomething(index: i) }
}
}
}

Using Array's Indices

The indices property is a range of numbers.

struct ContentView: View {
@State private var array = [1, 1, 2]

func doSomething(index: Int) {
self.array = [1, 2, 3]
}

var body: some View {
ForEach(array.indices) { i in
Text("\(self.array[i])")
.onTapGesture { self.doSomething(index: i) }
}
}
}

display index of each item in forEach loop in swift ui

For Swift Use .enumerated() with array to get index with item in for loop

let array = ["element1", "element2", "element3", "element4"]

for (index,item) in array.enumerated() {
print(index,item)
}

for SwiftUI this link will help you

Get index in ForEach in SwiftUI

Using Range and Count

struct ContentView: View {
@State private var array = [1, 1, 2]

func doSomething(index: Int) {
self.array = [1, 2, 3]
}

var body: some View {
ForEach(0..<array.count) { i in
Text("\(self.array[i])")
.onTapGesture { self.doSomething(index: i) }
}
}
}

Using Indices to get Index in a ForEach loop SwiftUI

In the variant of indices, you should use self as id

ForEach(self.postViewModel.posts.indices, id: \.self) { post in

Possible variant to have both

ForEach(Array(self.postViewModel.posts.enumerated()), 
id: \.1.postId) { (index, post) in

SwiftUI get position in Foreach

You should use .enumerated(), with the id as \.element.id.

ForEach(Array(loader.outfitcards.enumerated()), id: \.element.id) { (index: Int, outfit: Outfit) in
/* ... */
}

SwiftUI MVVM how to iterate and get index of array

You can use enumerated to have both index and element, like

    var body: some View {
ForEach(Array(self.viewModel.variantGroup.enumerated()), id: \.1) { index, vg in
/*** I Need to get the index of each iteration here, how? ***/
VStack {

SwiftUI ForEach get element AND index in 2d array

You can use a different init of the ForEach view:

ForEach(0..<array.endIndex) { index in //inner ForEach
VStack {
ReviewChart(dataModel: CalorieViewModel(),
valueHeight: array[index],
cornerRadius: 5,
color: index)
}
}

How to get the index of a dynamic List / ForEach bindable element (new Xcode 13's syntax)?

You can build wrapper by yourself:

struct ListIndexed<Content: View>: View {
let list: List<Never, Content>

init<Data: MutableCollection&RandomAccessCollection, RowContent: View>(
_ data: Binding<Data>,
@ViewBuilder rowContent: @escaping (Data.Index, Binding<Data.Element>) -> RowContent
) where Content == ForEach<[(Data.Index, Data.Element)], Data.Element.ID, RowContent>,
Data.Element : Identifiable,
Data.Index : Hashable
{
list = List {
ForEach(
Array(zip(data.wrappedValue.indices, data.wrappedValue)),
id: \.1.id
) { i, _ in
rowContent(i, Binding(get: { data.wrappedValue[i] }, set: { data.wrappedValue[i] = $0 }))
}
}
}

var body: some View {
list
}
}

Usage:

ListIndexed($items) { i, $item in
HStack {
Text("Index \(i)")
TextField("", text: $item.text)
}
}

SwiftUI get next item in ForEach loop

you could try adding a id to your struct Item, such as:

struct Item: Identifiable, Decodable, Hashable {
let id = UUID()
let card: Card
}

and then use:

VStack {
ForEach(item.cards, id: \.self) { theItem in
switch theItem.card.size {
case .Large:
LargeCard(card: theItem.card, viewModel: CardViewModel())
case .Medium:
MediumCard(card: theItem.card, viewModel: CardViewModel())
case .Small:
HStack(spacing: 16) {
SmallCard(card: theItem.card, viewModel: CardViewModel())
// here use the id to find the next item
if let ndx = item.cards.firstIndex(where: {$0.id == theItem.id}) {
if ndx + 1 < item.cards.count {
let nextItem = item.cards[ndx + 1]
if nextItem.card.size == .Small {
SmallCard(card: nextItem.card, viewModel: CardViewModel())
}
}
}
}
case .none:
Text("No more.")
}
}
}

You could also use enumerated as mentioned in the comments, such as:

VStack {
ForEach(Array(item.cards.enumerated()), id: \.offset) { index, theItem in
switch theItem.card.size {
case .Large:
LargeCard(card: theItem.card, viewModel: CardViewModel())
case .Medium:
MediumCard(card: theItem.card, viewModel: CardViewModel())
case .Small:
HStack(spacing: 16) {
SmallCard(card: theItem.card, viewModel: CardViewModel())
// here use the index to find the next item
if index + 1 < item.cards.count {
let nextItem = item.cards[index + 1]
if nextItem.card.size == .Small {
SmallCard(card: nextItem.card, viewModel: CardViewModel())
}
}
}
case .none:
Text("No more.")
}
}
}

Note, it looks like you should be using .environmentObject(viewModel) to pass
a single CardViewModel() to the views, instead of creating a new CardViewModel() each time.



Related Topics



Leave a reply



Submit