I'm trying to create table views based on both List
and ScrollView
, with a shared base view. My current attempt uses a builder-based approach, but requires closures with AnyView
type erasure.
My goal is to avoid using AnyView
type erasure, to improve performance, scalability, and design.
My attempts to re-design with generic type parameters have so far failed.
The simplified (and working) code example below displays only a single String
column, but captures the basic challenge. (In actuality, these are multi-column tables with various data types, specialized formatters, modifiers, etc.)
import SwiftUI
struct ContentView: View {
let data = ["a", "b", "c", "d"]
var body: some View {
HStack {
ListTable(title: "My List", data: data)
ScrollTable(title: "My Scroll", data: data)
}
}
}
struct ListTable<T: Hashable>: View {
var title: String, data: [T]
var body: some View {
BaseTable() { header, row in
VStack {
header(title)
List(data, id: \.self) { row($0) }
}
}
}
}
struct ScrollTable<T: Hashable>: View {
var title: String, data: [T]
var body: some View {
BaseTable() { header, row in
VStack {
header(title)
ScrollView { ForEach(data, id: \.self) { row($0) } }
}
}
}
}
struct BaseTable<Content: View, T: Hashable>: View {
typealias HBuilder = (String) -> AnyView
typealias RBuilder = (T) -> AnyView
var builder: (@escaping HBuilder, @escaping RBuilder) -> Content
var body: some View {
// NOTE this is where I'd like to avoid type-erasure to AnyView
builder({ AnyView( Text("Header \($0)") )},
{ AnyView( Text("Row \(String(describing: $0))") ) })
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View { ContentView() }
}
Two related questions that didn't quite provide a solution: