In SwiftUI, we have List
to represent reusable items. Just like UITableView
in UIKit
.
Static lists builds like this:
List {
Text("cell")
Text("cell")
Text("cell")
Text("cell")
}
But seems like it's not reusable at all
How can I have an array of some objects and fill the list based on the array and its dynamic size (count)?
Cell are reused.
See Does the List in SwiftUI reuse cells similar to UITableView?
For static Lists the limit are 10 Items.
This has to do with the ViewBuilder
implementation.
extension ViewBuilder {
public static func buildBlock<C0, C1>(_ c0: C0, _ c1: C1) -> TupleView<(C0, C1)> where C0 : View, C1 : View
}
…
extension ViewBuilder {
public static func buildBlock<C0, C1, C2, C3, C4, C5, C6, C7, C8, C9>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3, _ c4: C4, _ c5: C5, _ c6: C6, _ c7: C7, _ c8: C8, _ c9: C9) -> TupleView<(C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where C0 : View, C1 : View, C2 : View, C3 : View, C4 : View, C5 : View, C6 : View, C7 : View, C8 : View, C9 : View
}
To use an array you can use this API:
let array = [1,2,3,4]
let listView = List(array) { value in
Text(value.description)
}
extension List {
extension List {
/// Creates a List that computes its rows on demand from an underlying
/// collection of identified data.
@available(watchOS, unavailable)
public init<Data, RowContent>(_ data: Data, selection: Binding<Selection>?, rowContent: @escaping (Data.Element.IdentifiedValue) -> RowContent) where Content == ForEach<Data, HStack<RowContent>>, Data : RandomAccessCollection, RowContent : View, Data.Element : Identifiable
…
Dynamic views usually generated from dynamic data. So you should consider using a data structure for your repeating views, then build the list based on data like this:
struct Student: Identifiable {
let name: String
let id: Int
}
struct ContentView : View {
// Could be `@State Var` instead
let students = [
Student(name: "AAAAA", id: 1),
Student(name: "BBBBB", id: 2),
Student(name: "CCCCC", id: 3), // Notice that trailing comma is not problem here?
]
var body: some View {
List(students) { student in
Text(student.name)
}
}
}
Array should contain Identifiable
objects (Recommended)
or if you not prefer to conform to Identifiable
protocol you can use it like this:
struct Book {
let anyPropertyName: String
let title: String
}
struct ContentView : View {
// Could be `@State Var` instead
let books = [
Book(anyPropertyName: "AAAA", title: "1111"),
Book(anyPropertyName: "BBBB", title: "2222"),
Book(anyPropertyName: "CCCC", title: "3333")
]
var body: some View {
List(books.identified(by: \.anyPropertyName)) { book in
Text(book.title)
}
}
}
Note that dataSource can be @State var
and it gives the ability to update the UI whenever any @State var
changes.
Lastly, although it seems like it's not reusing, but actually it is! The limit of 10 static items has nothing to do with reusing.