はじめに
SwiftUIでiPad(横向き固定)のMaster Detail(SplitView)を作成するのに、かなり手こずった。
記述することは多くないし結果としては簡単な内容なのだが、ハマるとなかなか目的を果たせないので、記事として残しておく。
マスタ(左側テーブルビュー)の表示
struct MasterDetail1View: View {
@State private var fruits = ["Apple", "Banana", "Cherry", "Dragon Fruit"]
@State private var selectedFruit = ""
var body: some View {
NavigationView {
List {
ForEach(fruits, id: \.self) { fruit in
Text(fruit)
.onTapGesture {
self.selectedFruit = fruit
}
}
.onAppear {
self.selectedFruit = "Apple"
}
}
// 常に2カラムで良いのでナビゲーションバーは非表示
.navigationBarHidden(true)
}
}
}
デフォルトだと左上端ににマスター(左テーブルビュー)表示/非表示のアイコンが表示される。常にマスタ(左側テーブルビュー)表示で固定したいので.navigationBarHidden
をtrue
にする。
選択セルに色を付ける
struct MasterDetail2View: View {
@State private var fruits = ["Apple", "Banana", "Cherry", "Dragon Fruit"]
@State private var selectedFruit = ""
var body: some View {
NavigationView {
List {
ForEach(fruits, id: \.self) { fruit in
// テキスト以外の部分(セル全体)も含めてひとつの表示領域にする。
HStack{
Text(fruit)
Spacer()
}
// 形状を矩形全体とする。
.contentShape(Rectangle())
.onTapGesture {
self.selectedFruit = fruit
}
// 選択セル色を付ける
.listRowBackground(self.selectedFruit == fruit ? Color.gray.opacity(0.25) : Color.clear)
}
.onAppear {
self.selectedFruit = "Apple"
}
}
.navigationBarHidden(true)
}
}
}
タップイベントをを取得するために.onTapGesture
を記述。.listRowBackground
で色を設定。
Text
のみだとテキストの部分でしかタップイベントを取得できない。Spacer()
とともにHStack
で包み .contentShape(Rectangle())
を記述することでセル全体でタップイベントが取得できる。
Detail表示
struct MasterDetail3View: View {
@State private var fruits = ["Apple", "Banana", "Cherry", "Dragon Fruit"]
@State private var selectedFruit = ""
var body: some View {
NavigationView {
List {
ForEach(fruits, id: \.self) { fruit in
HStack{
Text(fruit)
Spacer()
}
.contentShape(Rectangle())
.onTapGesture {
self.selectedFruit = fruit
}
.listRowBackground(self.selectedFruit == fruit ? Color.gray.opacity(0.25) : Color.clear)
}
.onAppear {
self.selectedFruit = "Apple"
}
}
.navigationBarHidden(true)
// セルの表示形式を横幅いっぱいにする
.listStyle(PlainListStyle())
// Listと同じ階層にDetailを配置する
Detail(title: selectedFruit)
}
}
}
struct Detail: View {
let title: String
var body: some View {
Text("\(self.title)").font(.system(size: 50)).frame(maxWidth: .infinity)
}
}
Detail用のView
をList
の下に記述するだけで右側にDetail
を表示することはできるが、それだけだとマスタ(左側テーブルビュー)の表示にパディングができる。
.listStyle(PlainListStyle())
を記述することで、横幅いっぱいのマスタ(左側テーブルビュー)として表示できる。