Does anyone know how to implement a view (table/grid/collection) like these?
I have been at it for a while now and cannot figure it out. I’m pretty new to Swift which has not helped, but essentially the table should be horizontally and vertically scrollable (but not simultaneously, so there shouldn’t be any “diagonal” scrolling), and should have a pinned header row (which “pushes” at the end of the table) and a pinned column.
I’ve seen this in two different apps which makes me think it should be relatively simple but I cannot seem to get it right. I have been using SwiftUI but maybe it is just too complex and I need to fall back to UIKit.
Here is something that feels close:
import SwiftUI
struct Team {
let teamId: Int
let city: String
let name: String
}
struct ScrollableTableView: View {
@State private var teams = [
Team(teamId: 1610612737, city: "Atlanta", name: "Hawks"),
Team(teamId: 1610612738, city: "Boston", name: "Celtics"),
Team(teamId: 1610612739, city: "Cleveland", name: "Cavaliers"),
Team(teamId: 1610612740, city: "New Orleans", name: "Pelicans")
]
var body: some View {
let columns = [
GridItem(.fixed(120), alignment: .leading), // Pinned first column
GridItem(.fixed(150), alignment: .leading),
GridItem(.fixed(200), alignment: .leading)
]
ScrollView([.vertical], showsIndicators: true) {
ZStack {
ScrollView([.horizontal]) {
LazyVGrid(columns: columns, alignment: .leading, pinnedViews: [.sectionHeaders]) {
// Pinned Header Section
Section(header: headerView) {
// Table Rows
ForEach(teams) { team in
Section(header: Text("") // Pinned column
.frame(height: 40)
.padding(.horizontal, 4)) {
Text(team.city)
.frame(height: 40)
.padding(.horizontal, 4)
.border(Color(.separator), width: 0.5)
Text(team.name)
.frame(height: 40)
.padding(.horizontal, 4)
.border(Color(.separator), width: 0.5)
}
.background(Color(.systemBackground))
}
}
}
}
LazyVGrid(columns: [columns[0]], alignment: .leading, pinnedViews: [.sectionHeaders]) {
Section(header: Text("Team ID")
.frame(width: 120, height: 40, alignment: .leading)
.bold()
.padding(.horizontal, 4)
.background(Color(.systemGray5))
.border(Color(.separator), width: 0.5)) {
ForEach(teams) { team in
Text(String(team.teamId)) // Pinned column
.frame(width: 120, height: 40)
.padding(.horizontal, 4)
.background(Color(.systemGray6))
.border(Color(.separator), width: 0.5)
}
}
}
}
}
.border(Color(.separator), width: 1)
}
private var headerView: some View {
HStack(spacing: 0) {
Text("")
.frame(width: 120, height: 40, alignment: .leading)
.bold()
.padding(.horizontal, 4)
.background(Color(.systemGray5))
.border(Color(.separator), width: 0.5)
Text("City")
.frame(width: 150, height: 40, alignment: .leading)
.bold()
.padding(.horizontal, 4)
.background(Color(.systemGray5))
.border(Color(.separator), width: 0.5)
Text("Name")
.frame(width: 200, height: 40, alignment: .leading)
.bold()
.padding(.horizontal, 4)
.background(Color(.systemGray5))
.border(Color(.separator), width: 0.5)
}
.background(Color(.systemGray5))
}
}
#Preview {
ScrollableTableView()
}
1