SwiftUIにて、表示固定部分と横スクロール部分を水平に配置し、
全体としては縦スクロールするグリッドを作成する。
実装コードはこちら。
全体の ScrollView を [.vertical] として縦スクロールさせつつ、
入れ子にした ScrollView は [.horizontal] として横スクロールさせています。
ContentView.swift
import SwiftUI
var columnWidth: CGFloat = 60 // 列幅
var rowHeight: CGFloat = 60 // 行高さ
var rowCount: Int = 50 // 表示行数
struct ContentView: View {
// 大文字アルファベットの配列
// ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
let Alphabets = (65...90).map{ String(Character(UnicodeScalar($0)!)) }
var body: some View {
ScrollView([.vertical]) { // 全体としては縦スクロールさせる
HStack {
// タイトル列
ScrollView {
ForEach(1..<rowCount + 1) { rowNum in
TitleColumns(rowNum: "\(rowNum)")
}
}
.frame(maxWidth: columnWidth) // 列幅
// データ列
ScrollView([.horizontal]) { // データ列は横スクロールさせる
ForEach(1..<rowCount + 1) { rowNum in
DataColumns(rowNum: "\(rowNum)", items: Alphabets)
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
.padding(.horizontal, 20)
.padding(.vertical, 20)
}
}
}
// タイトル列
struct TitleColumns: View {
var rowNum: String
var body: some View {
LazyVGrid(
columns: Array(
repeating: .init(),
count: 1 // 列数
)
) {
ZStack {
Rectangle()
.frame(height: rowHeight) // 行高さ
.foregroundColor(.green)
Text("\(rowNum)")
.foregroundColor(.white)
}
}
}
}
// データ列
struct DataColumns: View {
var rowNum: String
var items: [String]
var body: some View {
LazyVGrid(
columns: Array(
repeating: .init(.fixed(columnWidth)), // 列幅
count: items.count
)
) {
ForEach(items, id: \.self) { item in
ZStack {
Rectangle()
.frame(height: rowHeight) // 行高さ
.foregroundColor(.gray)
Text("\(item)\(rowNum)")
.foregroundColor(.white)
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
.previewInterfaceOrientation(.portrait)
}
}
大文字アルファベットの配列の作成は以下を引用させていただきました。