SwiftUI Tutorial : Creating and Combining Viewsやってみた

SwiftUIの勉強でTutorialをやっていってるメモ書きです。
ちなみに今回は「[Creating and Combining Views](https://developer.apple.com/tutorials/swiftui/creating-and-combining-views)」をやっていきます。

リポジトリはこちら「[toshihirooya/SwiftUI-Tutorial](https://github.com/toshihirooya/SwiftUI-Tutorial)」

大体時間にして40minぐらいのチュートリアルみたいです。
あと、チュートリアルの検証環境は下記のような感じ。

|環境|バージョン|
|:---:|:---:|
|mac os|10.15.2|
|Xcode|11.3|

## Section 1. Create a New Project and Explore the Canvas
- 検証用のプロジェクトを用意する。
    - Project名「Landmarks」
    - User Interfaceはもちろん「SwiftUI」を選択する。
- Xcodeの`Resume`ボタンタップするとプレビューが表示されます。
- デフォルトのプロジェクトだとSwiftUIでは下記のような二つのStructで構成されていて、一つ目の構造体がViewを定義するもので、二つ目の構造体がプレビューを構成しています。

```ContentView.swift
import SwiftUI

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

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

## Section 2. Customize the Text View
- 続いてTextViewをカスタマイズしていきます。
- まずはコードを下記のように修正して
    - Textの文字列を「Tutorial Rock」にする。
    - fontを「.title」に設定
    - テキストの色を「.green」に設定
- TextのアトリビュートをメソッドチェーンでつなげてBuilder形式っぽく設定していく感じ

```ContentView.swift
struct ContentView: View {
    var body: some View {
        Text("Tutorial Rock")
            .font(.title)
            .foregroundColor(.green)
    }
}
```
- あと、PreviewからもViewの修正ができるようです。

|PreviewでViewを`⌘+Click`でメニュー表示|`Show SwiftUI Inspector...`選択で設定を変更できる|
|:---:|:---:|
|<img width="372" alt="スクリーンショット 2020-01-21 11.53.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126555/83d7f03f-4f2a-c85a-bca8-395b6f7226a0.png">|<img width="354" alt="スクリーンショット 2020-01-21 11.53.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126555/fdd7d33c-a276-2cdf-dcff-287f65c363cf.png">|

- あと、コードを`⌘ + クリック`してもViewのアトリビュートを設定できる

|Textを`⌘ + Click`する|Show SwiftUI Inspector...で設定できる|
|:---:|:---:|
|<img width="422" alt="スクリーンショット 2020-01-21 13.20.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126555/f16d414d-0f29-8190-eb39-9b61205a1330.png">|<img width="413" alt="スクリーンショット 2020-01-21 13.20.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126555/d72af277-69ef-f15f-0e66-c0422c288861.png">|

- 最後にコードを修正すると自動でPreviewにも反映されます。

## Section 3. Combine Views Using Stacks
- 続いてStackを駆使してViewを並べていきます。
- HStackにembeddedされているTextの間にSpacerを設定するとTextが画面の端にくるぐらいのSpaceが入るみたい。


```ContentView.swift
struct ContentView: View {
    var body: some View {
        VStack(alignment: .leading) {
            Text("Tutorial Rock")
                .font(.title)
            HStack {
                Text("Joshua Tree National Park")
                    .font(.subheadline)
                Spacer()
                Text("California")
                    .font(.subheadline)
            }
        }
        .padding()
    }
}
```

<img width="230" alt="スクリーンショット 2020-01-21 14.29.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126555/5485814e-45e3-dbf5-09fe-2745c004d8d0.png">

## Section 4. Create a Custom Image View
- 続いてカスタムViewを作っていきます。作るCustomViewはImageを円形に切り抜くViewです。
- まずはSwiftUIの新しいファイルを追加します。

<img width="735" alt="スクリーンショット 2020-01-21 14.53.24.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126555/8188a214-94de-40fe-3359-4418117f6d05.png">

- ファイルが追加できたらImageを画面中央に追加します。

```CircleImage.swift
struct CircleImage: View {
    var body: some View {
        Image("safari")
    }
}

struct CircleImage_Previews: PreviewProvider {
    static var previews: some View {
        CircleImage()
    }
}
```
<img width="235" alt="スクリーンショット 2020-01-21 15.01.03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126555/71adadc1-f2d7-db95-b9ae-8c14e7d9cacc.png">

- 続いてCircleImageを作っていきます。

|Imageを円形にした|Imageの淵を灰色にした|影をつけた|Imageの淵を白色にした|
|:---:|:---:|:---:|:---:|
|<img width="226" alt="スクリーンショット 2020-01-21 15.18.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126555/af2003bc-ebff-e83d-ed97-44776f9f4819.png">|<img width="223" alt="スクリーンショット 2020-01-21 15.18.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126555/f3bcb825-0168-77ab-f785-61e5675a4796.png">|<img width="225" alt="スクリーンショット 2020-01-21 15.19.03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126555/3af53594-fd16-32e4-7d73-a5c6dabaf51e.png">|<img width="225" alt="スクリーンショット 2020-01-21 15.19.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126555/2bad1254-bd05-9efe-d83a-2276133115f5.png">|



```CircleImage.swift
struct CircleImage: View {
    var body: some View {
        Image("safari")
            .clipShape(Circle()) // Imageを円形に切り出す
            .overlay(Circle().stroke(Color.white, lineWidth: 4)) // 切り出したImageの淵に線を描く
            .shadow(radius: 10) // 影をつける
    }
}
```

## Section 5. Use UIKit and SwiftUI Views Together
- 続いてMapKitを使ってMapを表示するviewの作成をやっていきます


```MapView.swift
import SwiftUI
import MapKit

struct MapView: UIViewRepresentable {
    func makeUIView(context: Context) -> MKMapView {
        MKMapView(frame: .zero)
    }
    
    func updateUIView(_ view: MKMapView, context: Context) {
        let coordinate = CLLocationCoordinate2D(
            latitude: 34.011286, longitude: -116.166868)
        let span = MKCoordinateSpan(latitudeDelta: 2.0, longitudeDelta: 2.0)
        let region = MKCoordinateRegion(center: coordinate, span: span)
        view.setRegion(region, animated: true)
    }
}

struct MapView_Previews: PreviewProvider {
    static var previews: some View {
        MapView()
    }
}
```
- Previewの再生ボタンを押すと地図が表示される。

<img width="977" alt="スクリーンショット 2020-01-21 15.49.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126555/e83d6b32-d875-386e-4a36-135d92228e9a.png">

## Section 6. Compose the Detail View

- あとは作ったViewを組み合わせていきます。

```ContentView.swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            MapView()
                .edgesIgnoringSafeArea(.top)
                .frame(height: 300)

            CircleImage()
                .offset(y: -130)
                .padding(.bottom, -130)
            
            VStack(alignment: .leading) {
                Text("Tutorial Rock")
                    .font(.title)
                HStack {
                    Text("Joshua Tree National Park")
                        .font(.subheadline)
                    Spacer()
                    Text("California")
                        .font(.subheadline)
                }
            }
            .padding()

            Spacer()

        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
```
- 最後に完成形がこちら

<img width="485" alt="スクリーンショット 2020-01-22 10.54.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126555/10ed82a6-d752-85b6-42be-c332a76e65ed.png">