【SwiftUI入門講座Part3】SwiftUIの基本である「VStack・HStack・ZStack」を覚えよう

Part3では、VStack、HStack、ZStackについて解説していきたいと思います。ですが、それらを解説する前にコードの構成について解説していきます。

コードの構成について

まず、プロジェクトを作成すると2つのファイルが作成されます。

プロジェクト名App.swiftと、ContentView.swiftの2つです。

プロジェクト名App.swift

中身はこんな感じになっています。

import SwiftUI

@main
struct HelloSwiftUIApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

ブロック単位で見ていくとこのようになっています。

structの中に、var bodyがあって、さらにその中にWindowGroupがあるという状況です。

このファイルでは、何をしているのかというと、最初に表示する画面を決めてるだけです。

WindowGroupの中に、ContentView()が書かれています。つまり、ContentView()が最初に表示される画面です。

ContentView.swift

上記で呼んでいるContentView()がこちらのファイルです。

import SwiftUI

struct ContentView: View {
    var body: some View {
        Text("Hello, world!")
            .padding()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

ブロック単位で見ていくと2つに分かれています。

上のブロックは、structの中に、var bodyがあります。

下のブロックは、structの中に、static var previewsがあります。

このファイルは、最初に表示される画面のレイアウトを書くためのファイルです。

上のブロックのvar bodyの中に、色々とオブジェクトを書いてレイアウトを作っていきます。

では、下のブロックは何かというと、下のブロックは、プレビューを表示させるコードになります。試しに下のコードを削除してみると、プレビュー部分が消えると思います。

なので、プレビュー機能を使わないならこのコードは必要ありません。

VStack、HStack、ZStackとは?

まず、この3つのStackを覚えるところからSwiftUIは始まると思います。

Textを縦に3つ並べるときに、var bodyの中にTextを3つ書くと、このようにプレビューでは3つの画面で表示されてしまいます。。

では、3つのTextVStackの中に入れてみましょう。

綺麗に縦に並びました。SwiftUIはこのようにオブジェクトをStackにどんどん入れてレイアウトを作成していきます。

Stackというのは並べていれる箱だと思ってください。

じゃあ、VStackというのは、VはVerticalの略なので、縦に並べる箱です。

じゃあ、HStackというのは、HはHorizontalの略なので、横に並べる箱です。

じゃあ、ZStackというのは、Z軸とかのZの意味なので、重ねて並べる箱です。

まずはこの3つをしっかりと覚えましょう。

VStack、HStack、ZStackで並べてみる

では、このサイズが異なる3つのViewをVStack、HStack、ZStackに入れてみます。

VStackの場合、このように縦に並びます。

HStackの場合、このように横に並びます。

ZStackの場合、このように重なります。

新しくプロジェクトを作成し、以下のコードをContentView.swiftに書いて右上のResumeボタンを押して画面を確認してみましょう。

struct ContentView: View {
    var body: some View {
        VStack {
            Rectangle()
                .foregroundColor(.blue)
                .frame(width: 200, height: 200)
            Rectangle()
                .foregroundColor(.red)
                .frame(width: 150, height: 150)
            Rectangle()
                .foregroundColor(.yellow)
                .frame(width: 100, height: 100)
        }
    }
}
struct ContentView: View {
    var body: some View {
        HStack {
            Rectangle()
                .foregroundColor(.blue)
                .frame(width: 150, height: 150)
            Rectangle()
                .foregroundColor(.red)
                .frame(width: 100, height: 100)
            Rectangle()
                .foregroundColor(.yellow)
                .frame(width: 50, height: 50)
        }
    }
}
struct ContentView: View {
    var body: some View {
        ZStack {
            Rectangle()
                .foregroundColor(.blue)
                .frame(width: 200, height: 200)
            Rectangle()
                .foregroundColor(.red)
                .frame(width: 150, height: 150)
            Rectangle()
                .foregroundColor(.yellow)
                .frame(width: 100, height: 100)
        }
    }
}

このVStack、HStack、ZStackを織り交ぜてUIを作るのがSwiftUIの基本です。

四角のViewについて

ちなみに、Rectangle()で四角のViewが作れます。
.foregroundColor(.blue)でViewの色を決められます。
.frame(width: 200, height: 200)で幅と高さを決めることができます。

Rectangle()
    .foregroundColor(.blue)
    .frame(width: 200, height: 200)

少し複雑なレイアウトを作ってみる

では、このような画面を作るとなると、どうなるのかというと

①VStackの中に、グレーと、紫とHStackとZStackが入っています。
②HStackには、青と、赤と、黄色が入っています。
③ZStackには、緑とHStackが入っています。
④HStackには、VStackが2つ入っています。
⑤左のVStackには、ピンクと黒が入っていて、右のVStackには、白と黄色が入っています。

という構成です。。ちょっとややこしいですが、こんな感じでレイアウトを組んでいくのがSwiftUIです。

struct ContentView: View {
    var body: some View {
        VStack {
            Rectangle()
                .foregroundColor(.gray)
                .frame(width: 350, height: 100)
            Rectangle()
                .foregroundColor(.purple)
                .frame(width: 350, height: 100)
            HStack {
                Rectangle()
                    .foregroundColor(.blue)
                    .frame(width: 150, height: 150)
                Rectangle()
                    .foregroundColor(.red)
                    .frame(width: 100, height: 100)
                Rectangle()
                    .foregroundColor(.yellow)
                    .frame(width: 50, height: 50)
            }
            ZStack {
                Rectangle()
                    .foregroundColor(.green)
                    .frame(width: 350, height: 200)
                HStack {
                    VStack {
                        Rectangle()
                            .foregroundColor(.pink)
                            .frame(width: 150, height: 70)
                        Rectangle()
                            .foregroundColor(.black)
                            .frame(width: 150, height: 70)
                    }
                    VStack {
                        Rectangle()
                            .foregroundColor(.white)
                            .frame(width: 150, height: 70)
                        Rectangle()
                            .foregroundColor(.yellow)
                            .frame(width: 150, height: 70)
                    }
                }
            }
        }
    }
}

演習問題

問題①

このようなレイアウトを組んでみましょう。(ハンバーガーのつもり)

struct ContentView: View {
    var body: some View {
        VStack {
            Rectangle()
                .foregroundColor(.orange)
                .frame(width: 200, height: 50)
            Rectangle()
                .foregroundColor(.red)
                .frame(width: 180, height: 20)
            Rectangle()
                .foregroundColor(.yellow)
                .frame(width: 180, height: 20)
            Rectangle()
                .foregroundColor(.brown)
                .frame(width: 180, height: 20)
            Rectangle()
                .foregroundColor(.green)
                .frame(width: 180, height: 20)
            Rectangle()
                .foregroundColor(.orange)
                .frame(width: 200, height: 50)
        }
    }
}

問題②

このようなレイアウトを組んでみましょう。(クリーパーのつもり)

struct ContentView: View {
    var body: some View {
        ZStack {
            Rectangle()
                .foregroundColor(.green)
                .frame(width: 300, height: 300)
            VStack {
                HStack {
                    Rectangle()
                        .foregroundColor(.black)
                        .frame(width: 70, height: 70)
                    Rectangle()
                        .foregroundColor(.black)
                        .frame(width: 70, height: 70)
                }
                Rectangle()
                    .foregroundColor(.black)
                    .frame(width: 50, height: 20)
                Rectangle()
                    .foregroundColor(.black)
                    .frame(width: 100, height: 80)
            }
        }
    }
}

問題③

このようなレイアウトを組んでみましょう。(ミニオンのつもり)

struct ContentView: View {
    var body: some View {
        VStack {
            ZStack {
                Rectangle()
                    .foregroundColor(.yellow)
                    .frame(width: 300, height: 300)
                VStack {
                    HStack {
                        Rectangle()
                            .foregroundColor(.black)
                            .frame(width: 60, height: 20)
                        ZStack {
                            Rectangle()
                                .foregroundColor(.gray)
                                .frame(width: 90, height: 90)
                            Rectangle()
                                .foregroundColor(.white)
                                .frame(width: 70, height: 70)
                            Rectangle()
                                .foregroundColor(.black)
                                .frame(width: 20, height: 20)
                        }
                        ZStack {
                            Rectangle()
                                .foregroundColor(.gray)
                                .frame(width: 90, height: 90)
                            Rectangle()
                                .foregroundColor(.white)
                                .frame(width: 70, height: 70)
                            Rectangle()
                                .foregroundColor(.black)
                                .frame(width: 20, height: 20)
                        }
                        Rectangle()
                            .foregroundColor(.black)
                            .frame(width: 60, height: 20)
                    }
                    ZStack {
                        Rectangle()
                            .foregroundColor(.black)
                            .frame(width: 70, height: 40)
                        VStack {
                            Rectangle()
                                .foregroundColor(.white)
                                .frame(width: 60, height: 10)
                            Rectangle()
                                .foregroundColor(.red)
                                .frame(width: 60, height: 10)
                        }
                    }
                }
            }
            Rectangle()
                .foregroundColor(.blue)
                .frame(width: 300, height: 100)
            HStack {
                Rectangle()
                    .foregroundColor(.black)
                    .frame(width: 70, height: 30)
                Rectangle()
                    .foregroundColor(.black)
                    .frame(width: 70, height: 30)
            }
        }
    }
}

最後のミニオンは激ムズだと思います笑

今回は、Rectangle()の色と大きさ指定だけでここまでやってるので、ブサイクなミニオンが出来上がりましたが、色々と他のオブジェクトを使いながらやるともっと近づくと思います!

近づけるためにもっと知識をつけましょう!