SwiftUI List の高さを、項目の数と高さに合わせてちょうどフィットさせる
サンプルは 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 // I don't want to use fixed value. But i don't know right way. 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)) // Important! } .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 の高さを項目の数・高さに対して、ピッタリ設定することはできた。