iPhoneの写真アプリのように、画像などをタイル上に並べてレイアウトするいわゆるGridLayoutの方法を説明します。
環境
- Xcode12.5.1
- iOS14.6
- スクショはiPhone12Pro Maxで撮影
まずは縦に並べる方法を確認
GridLayoutを実現するにはList
を使用します。なのでまずはList
の使用方法をおさらいしましょう。
struct ContentView: View {
var body: some View {
List(1..<11) { _ in
Image("Image")
}
}
}
縦に並べるだけならこんな感じで簡単に実装できます。List
ではなくVStack
を使用してもOKです。
水平に並べる
では次に画像を水平に並べてみましょう。
水平に並べるにはHStack
を使用します。
struct ContentView: View {
var body: some View {
HStack {
ForEach(1..<6) { _ in
Image("Image")
}
}
}
}
これもとても簡単ですね。これでは横スクロールはできませんが、今回は横スクロールは不要なので説明は省きます。
縦横を組み合わせる
これらを組み合わせることで以下のような見た目になります。
struct ContentView: View {
var body: some View {
List(1..<11) { _ in
HStack {
ForEach(1..<6) { _ in
Image("Image")
}
}
}
}
}
とりあえずこれで縦横に画像を並べることができました。
サイズの調整
並べることはできましたが、画面のサイズに対して画像が大きすぎますよね。横にちょうど5つ並ぶように調整してみましょう。
横にちょうど5つ並べるためには、画像のサイズを画面横幅÷5にすれば良さそう。ということで以下のように、GeometryReader
を使って実装します。
struct ContentView: View {
var body: some View {
GeometryReader { geometry in
List(1..<11) { _ in
HStack {
ForEach(1..<6) { _ in
Image("Image")
.resizable()
.frame(width: geometry.frame(in: .global).width/5 , height: geometry.frame(in: .global).width/5)
}
}
}
}
}
}
それっぽくなってきましたが、5つ目の画像が切れてしまってます。そうです、余白分を考慮しないとちょうどいい感じに表示されません。
余白をなくす
では余白を無くしましょう。
ポイントは2つです。
まず、List
によってできてしまう余白を削除するために.listRowInsets(EdgeInsets())
を使用します。この時、List
内の表示にはForEach
を使用してください。でないと.listRowInsets(EdgeInsets())
が効きません。
もう一つはHStackでできてしまう余白を消すためにHStack(spacing: 0)
を指定することです。
struct ContentView: View {
var body: some View {
GeometryReader { geometry in
List {
ForEach(1..<11) { _ in
HStack(spacing: 0) {
ForEach(1..<6) { _ in
Image("Image")
.resizable()
.frame(width: geometry.frame(in: .global).width/5 , height: geometry.frame(in: .global).width/5)
}
}
.listRowInsets(EdgeInsets())
}
}
}
}
}
Listの横線を消す
これでほぼほぼ完成ですが、最後に不要な横線を消しましょう。
これが意外と面倒です。iOS15以降でしたら.listRowSeparator(.hidden)
を設定してあげれば済むのですが、iOS14以前ではそうはいきません。
iOS14を対象にしたい場合はListではなくVStackを使用しましょう
struct ContentView: View {
var body: some View {
GeometryReader { geometry in
ScrollView {
VStack(spacing: 0) {
ForEach(1..<11) { _ in
HStack(spacing: 0) {
ForEach(1..<6) { _ in
Image("Image")
.resizable()
.frame(width: geometry.frame(in: .global).width/5 , height: geometry.frame(in: .global).width/5)
}
}
.listRowInsets(EdgeInsets())
}
}
}
}
}
}
iOS13以前だけが対象なら、UITableView.appearance().separatorStyle = .none
を指定することで消すことができます。
struct ContentView: View {
init() {
UITableView.appearance().tableFooterView = UIView()
UITableView.appearance().separatorStyle = .none
}
var body: some View {
GeometryReader { geometry in
List {
ForEach(1..<11) { _ in
HStack(spacing: 0) {
ForEach(1..<6) { _ in
Image("Image")
.resizable()
.frame(width: geometry.frame(in: .global).width/5 , height: geometry.frame(in: .global).width/5)
}
}
.listRowInsets(EdgeInsets())
}
}
}
}
}
おわり
今回は以上です。VStackとHStackの組み合わせで表示するのが無難ですね。
コメント