SwiftUI - アプリ開発 それっぽくViewを並べてみた。

題名通り、それっぽくViewを並べてみました。
とりあえず配置してみただけですが、色々勉強できました。

今回は適当にViewを並べてみましたが、SwiftUIはpaddingやSpacerというものがあるおかげでViewを綺麗に配置できるのがかなりいいなと個人的に思いました。

コードで学べるものとしていくつかあげてみたので、興味があれば実装してみてください。


![SwiftUI-demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274108/c2afae0b-b102-88f4-082e-c3f3d8784bfb.gif)

## 学べるもの
・Identifiableプロトコルの実装
・View間のデータの受け渡し
・@State,@Bindingを使うタイミング
・HStack, VStack, ScrollView
・各Viewが持つそれぞれのプロパティ
・ForEachの使い方
・画像を丸くする
・toggle()
　などなど


## 実装

### Identifiableプロトコルの実装
```Swift
struct Images:Identifiable {
    var id = UUID() //←識別子のプロパティを必ず用意ければいけないようです。
    var name: String
    var img:String
}
```
### メインとなるView
```Swift
struct ContentView: View {
    //@Stateをつけると変更時View再描写される
    //@BindingをつけるとView間での双方向のデータ共有が可能
    @State var flag:Bool = false
    @State var tapName:String = "tapNAME"
    
    private var images = [Images(name: "Xxxx Xxxx", img: "myimage"),
                          Images(name: "Aaaaa Aaaa", img: "myimage"),
                          Images(name: "Bbbbb Bbbb", img: "myimage"),
                          Images(name: "Ccccc Cccc", img: "myimage"),
                          Images(name: "Ddddd Dddd", img: "myimage"),
                          Images(name: "Eeeee Eeee", img: "myimage"),
                          Images(name: "Fffff Ffff", img: "myimage"),
                          Images(name: "Ggggg Gggg", img: "myimage")]
    
    
    var body: some View {
        VStack {
            ScrollView(.vertical, showsIndicators: false, content: {
                HStack {
                    Image(images.first?.img ?? "NoImage")
                        .resizable()
                        .frame(width: 75, height: 75)
                        .clipShape(Circle())
                        .overlay(Circle().stroke(Color.white,lineWidth: 1))
                        .shadow(radius: 10)
                        .padding(.leading)
                    
                    Text(images.first?.name ?? "NoName")
                        .font(.title2)
                        .fontWeight(.bold)
                        .foregroundColor(Color.white)
                        .padding(.leading)
                    
                    Spacer()
                    
                    Image(systemName: "bell.badge")
                        .font(.title)
                        .foregroundColor(Color.white)
                        .padding(.trailing)
                    
                }.padding(.top)
                
                Text(tapName).foregroundColor(.white)
                
                ScrollView(.horizontal, showsIndicators: false, content: {
                    HStack {
                        ForEach(images) { image in
                            CustomBtn(img: Image(image.img), name: image.name, flag: $flag, tapName: $tapName) //CustomBtnに変数を受け渡すため$を頭につける
                        }
                    }
                    HStack {
                        ForEach(images) { image in
                            CustomBtn(img: Image(image.img), name: image.name, flag: $flag, tapName: $tapName)
                        }
                    }
                }).padding(.top)
                //MARK:- First CollectionView
                VStack(alignment: .leading, spacing: nil, content: {
                    Text("First CollectionView")
                        .font(.title)
                        .foregroundColor(Color.white)
                        .fontWeight(.bold)
                        .padding(.top).padding(.leading)
                    ScrollView(.horizontal, showsIndicators: false, content: {
                        HStack {
                            ForEach(images) { image in
                                Image(image.img)
                                    .resizable()
                                    .frame(width: 150, height: 150, alignment: .center)
                                    .cornerRadius(5.0)
                            }
                        }.padding(.leading).padding(.trailing) //左右のみスペース
                    })
                })
                //MARK:- Seccond CollectionView
                VStack(alignment: .leading, spacing: nil, content: {
                    Text("Seccond CollectionView")
                        .font(.title)
                        .foregroundColor(Color.white)
                        .fontWeight(.bold)
                        .padding(.top).padding(.leading)
                    ScrollView(.horizontal, showsIndicators: false, content: {
                        HStack {
                            ForEach(images) { image in
                                Image(image.img)
                                    .resizable()
                                    .frame(width: 150, height: 150, alignment:.center)
                                    .cornerRadius(5.0)
                                    .clipShape(Circle())
                            }
                        }.padding(.leading).padding(.trailing)
                    })
                })
                //MARK:- Third CollectionView
                VStack(alignment: .leading, spacing: nil, content: {
                    Text("Third CollectionView")
                        .font(.title)
                        .foregroundColor(Color.white)
                        .fontWeight(.bold)
                        .padding(.top).padding(.leading)
                    ScrollView(.horizontal, showsIndicators: false, content: {
                        HStack {
                            ForEach(images) { image in
                                Image(image.img)
                                    .resizable()
                                    .frame(width: 250, height: 150, alignment:.center)
                                    .cornerRadius(5.0)
                            }
                        }.padding(.leading).padding(.trailing).padding(.bottom)
                    })
                })
                //-------
            })
        }.padding(.top)
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color(#colorLiteral(red: 0.09886621684, green: 0.1093793288, blue: 0.2782805264, alpha: 1)))
        .edgesIgnoringSafeArea(.all)
        
    }
}
```

画面上部のボタン（画像とテキスト）は以下Structを作成して参照しています。


```Swift
//CustomBtn
struct CustomBtn: View {
    let img:Image
    let name:String
    @Binding var flag:Bool
    @Binding var tapName:String //@BindingをつけるとView間での双方向のデータ共有が可能
    
    var body:some View {
        //Button
        Button(action: {
            //ここのセクション内にボタンを押したときの動作を書く
            self.flag.toggle() //false・true反転してくれる
            self.tapName = name
        }){
            img
                .resizable() //画像をいい感じにリサイズ
                .frame(width: 50, height: 50) //フレームサイズ
            Text(name)
                .font(.subheadline) //サイズ変更
                .fontWeight(.heavy) //太字
                .minimumScaleFactor(0.7) //最小文字サイズ（自動サイズ変更されるため）
                .lineLimit(2) //最大行数
                .foregroundColor(Color.white)
            
            Spacer()
            
        }.background(Color(#colorLiteral(red: 0.1695919633, green: 0.164103806, blue: 0.3997933269, alpha: 1)))
        .cornerRadius(5.0) //角を少し丸く
        .padding(.horizontal)
        
    }
}
```


基本的なViewの配置からView間のデータ受け渡しなどなどアウトプットしました。
どうしても独学だと、プログラムとしては動作しているけど、これが本当にベストプラクティスなのかいつも迷っています。。なのでもしこっちの方が綺麗に書けるとか早いなどなどあればコメントで教えていただけると嬉しいです。

今後も備忘録として、残していきたいと思います。