サンプルは GitHub にある。
List の高さが項目に対して、ちょうどフィットされていないと以下の課題が発生する
- List の高さが項目表示に足りない -> List 内スクロールが発生する
- List の高さが項目表示より大きい -> List が大きすぎて、見た目が悪い
これを解決したいため、SwiftUI の List の高さを、項目に応じて、ちょうどフィットする高さに調整する方法を調べた。
サンプルの動作は、上のようになる。
コードを抜粋すると以下だ。
struct RowView: View {
var name: String
var body: some View {
HStack {
Spacer().frame(width: 10)
Image(systemName: name).foregroundColor(.white)
Text(name).foregroundColor(.white)
Spacer()
}.listRowBackground(Color.blue)
}
}
struct ContentView: View {
let rows = [
"sun.min",
"sun.min.fill",
"sun.max",
"sun.max.fill",
"sunrise",
"sunrise.fill",
"sunset",
"sunset.fill",
"sun.dust",
"sun.dust.fill",
"sun.haze",
"sun.haze.fill",
"moon",
"moon.fill",
"moon.circle",
"moon.circle.fill",
]
static let rowHeight: CGFloat = 50
static let rowMargin: CGFloat = 0.5
var body: some View {
ScrollView(.vertical, showsIndicators: true) {
VStack {
Text("Weather Symbols").font(.largeTitle)
Spacer().frame(height: 10)
List {
ForEach(0..<rows.count) { (i) in
RowView(name: self.rows[i]).frame(height: ContentView.rowHeight)
}
.listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
}
.frame(height: CGFloat(rows.count) * (ContentView.rowHeight + ContentView.rowMargin))
Spacer()
}
}
.padding()
}
}
重要なのは以下だ。
まず、リスト内の項目の Insets(マージン)を無しにする。
List {
ForEach(0..<rows.count) { (i) in
}.listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
}
そして List 自体の高さを明示的に設定する。
この時、重要なのが項目に対して 0.5 をプラスしている箇所。
これが無いと List の高さが足りないためか、 List 内のスクロールが発生してしまう。
ここは 0.5 と固定で設定しているが、本来は SwiftUI から取得した値を使いたい。
しかし、それに当たるものを見つけることができなかった。
おそらく List の項目間にある Divider (仕切り線)の高さに相当するものだと思うだが・・・。
List {
}.frame(height: 項目の数 * (項目の高さ + 0.5))
まあ、とりあえず、こんな感じで List の高さを項目の数・高さに対して、ピッタリ設定することはできた。