Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
//
// IndexedForEach.swift
//
//
// Created by Soroush Khanlou on 1/21/20.
//
//
import Foundation
import SwiftUI
/// A ForEach that also provides the index with each element.
/// With love from https://stackoverflow.com/a/61149111/946049
struct IndexedForEach<Data: RandomAccessCollection, ID: Hashable, Content: View>: View {
var data: Data
var id: KeyPath<Data.Element, ID>
var content: (_ index: Data.Index, _ element: Data.Element) -> Content
var body: some View {
ForEach(
zip(self.data.indices, self.data).map { index, element in
return IndexInfo(
index: index,
id: self.id,
element: element
)
},
id: \.elementID
) { indexInfo in
self.content(indexInfo.index, indexInfo.element)
}
}
init(_ data: Data, id: KeyPath<Data.Element, ID>, content: @escaping (_ index: Data.Index, _ element: Data.Element) -> Content) {
self.data = data
self.id = id
self.content = content
}
}
extension IndexedForEach where ID == Data.Element.ID, Content: View, Data.Element: Identifiable {
init(_ data: Data, @ViewBuilder content: @escaping (_ index: Data.Index, _ element: Data.Element) -> Content) {
self.init(data, id: \.id, content: content)
}
}
struct IndexInfo<Index, Element, ID: Hashable>: Hashable {
let index: Index
let id: KeyPath<Element, ID>
let element: Element
var elementID: ID {
self.element[keyPath: self.id]
}
init(index: Index, id: KeyPath<Element, ID>, element: Element) {
self.index = index
self.id = id
self.element = element
}
static func == (_ lhs: IndexInfo, _ rhs: IndexInfo) -> Bool {
lhs.elementID == rhs.elementID
}
func hash(into hasher: inout Hasher) {
self.elementID.hash(into: &hasher)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment