3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

SwiftUIでMasterDetailを作成する

Last updated at Posted at 2020-12-28

はじめに

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)
        }
   }
}

image.png

デフォルトだと左上端ににマスター(左テーブルビュー)表示/非表示のアイコンが表示される。常にマスタ(左側テーブルビュー)表示で固定したいので.navigationBarHiddentrueにする。
image.png

選択セルに色を付ける

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())を記述することでセル全体でタップイベントが取得できる。
image.png

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用のViewListの下に記述するだけで右側にDetailを表示することはできるが、それだけだとマスタ(左側テーブルビュー)の表示にパディングができる。
image.png
.listStyle(PlainListStyle())を記述することで、横幅いっぱいのマスタ(左側テーブルビュー)として表示できる。
image.png

ソースコード

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?