【SwiftUI】GeometryReaderを使ったグリッドシステムを考える

# はじめに
SwiftUIでそれぞれのViewのレイアウトをデザインする時に必要なGeometryReaderを用いて、グリッドシステムを考えることを目的とする。

ただし、今回Iphone11、Iphone8、IpadPro12inchのそれぞれをSimulatorで確認しましたが、心から満足できるデザインになっていません。まだまだ改善が必要な点をご了承ください。

前回までの記事は以下を参考ください。

**参考記事**
[【SwiftUI】AppデザインのためにGeometryReaderを理解する](https://qiita.com/m37335/items/fd5d8b21e9ab9bc9fdda)


# 開発環境
OSX 10.15.7 (Catalina) 
Xcode 12.2.0
CocoaPods 1.10.0



# SwiftUIのレイアウトシステム

画面サイズいっぱいの１ページのViewを想定します。
縦にスクロールせず、横にスクロールもしない場合のAppデザインを考えます。
まずは画面全体を10分割しました。
そのためにGeometryReaderを用いて、それぞれのRow部分のframeに```.frame(width: container.size.width, height: container.size.height/10)```を実装しました。

![ContentView_swift_—_Edited.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/867981/1e5ac399-a5ca-a298-8f50-d70305202f59.png)

**参考文献**
[How to provide relative sizes using GeometryReader](https://www.hackingwithswift.com/quick-start/swiftui/how-to-provide-relative-sizes-using-geometryreader)

```swift
struct ContentView: View {
    
    var body: some View {
        
        // parent View
        VStack {
            // クロージャーの"g"は任意で設定可能
            GeometryReader { container in
                
                // Container
                VStack {
                    
                    // section1
                    ZStack {
                        
                        // a horizontal line
                        HStack{
                            
                            Image(systemName: "doc")
                            Text("First One")
                        }
                    // parentViewの幅いっぱい、縦は全体の1/10に設定。
                    }.frame(width: container.size.width, height: container.size.height/10, alignment: .center)
                    .border(Color.blue)
                    
                    // section2
                    ...略...
                }
            }
        }
    }
}
```

# グリッドシステムを考える
GeometryReaderを使って、画面サイズを10分割しました。
それらをX個分の高さを設定するために、```frame(width: container.size.width, height: container.size.height/10 * 4)```と記載内容を変更しました。"*4"を追加することによって、グリッドシステムを考えます。合計の比率を10になるように設定すれば、画面の高さの計算を簡単にすることができます。

下のイメージでは一つ目のセクションを"4"、二つ目のセクションを"4"、そして、三つ目のセクションを"2"で設定しました。

![gridView_swift.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/867981/68500aca-32f8-ba20-a052-43b57bb85c4c.png)

```swift
struct gridView: View {
    var body: some View {
        
        // parent View
        VStack {
            // クロージャーの"g"は任意で設定可能
            GeometryReader { container in
                
                // Container
                VStack {
                    
                    // section1
                    ZStack {
                        
                        // a horizontal line
                        HStack{
                            
                            Image(systemName: "doc")
                            Text("First One")
                        }
                    // parentViewの幅いっぱい、縦は全体の1/10に設定。
                    // Row部分を４つ分の高さを設定する。
                    }.frame(width: container.size.width, height: container.size.height/10 * 4, alignment: .center)
                    .border(Color.blue)
                    
                    // section2
                    ZStack {
                        
                        // a horizontal line
                        HStack{
                            
                            Image(systemName: "doc")
                            Text("Second One")
                        }
                    // parentViewの幅いっぱい、縦は全体の1/10に設定。
                    // Row部分を４つ分の高さを設定する。
                    }.frame(width: container.size.width, height: container.size.height/10 * 4, alignment: .center)
                    .border(Color.blue)
                    
                    // section3
                    ZStack {
                        
                        // a horizontal line
                        HStack{
                            
                            Image(systemName: "doc")
                            Text("Third One")
                        }
                    // parentViewの幅いっぱい、縦は全体の1/10に設定。
                    // Row部分を２つ分の高さを設定する。
                    }.frame(width: container.size.width, height: container.size.height/10 * 2, alignment: .center)
                    .border(Color.blue)
                    
                }
            }
        }.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
    }
}

```

#実装のイメージ
**Iphone11**
![iPhone_11_–_14_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/867981/d374fffd-a664-efd4-85f0-ab2725740a11.png)

**Iphone8**
![iPhone_8_–_14_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/867981/330dd93a-45b5-7149-0617-fb1afa62e115.png)

**iPad Pro（12.9inch）**
![iPad_Pro__12_9-inch__–_4th_generation_–_14_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/867981/83acde9d-d9dd-89e9-e8fb-8ba910af76f5.png)

iPad Pro（12.9inch）の方はデザインとバランスがあまり美しくないですね。Iphone8も悪くはないけど...って感じです。

特にPaddingの設定など余白については改善が必要です。

**参考文献**
[SwiftUI Shifting Display Left](https://developer.apple.com/forums/thread/133163)

```swift
struct imageView: View {
    
    @State var color = Color.black.opacity(0.7)
    @State var email = ""
    @State var pass = ""
    
    @State var visible = false
    
    var body: some View {
        
        ZStack(alignment: .topTrailing) {
            
            VStack {
                
                GeometryReader{container in
                    Color.init("pinkColor")
                    VStack {
                        
                        // Logo Section
                        VStack(alignment: .center) {
                            
                            GeometryReader{rowSection1 in
                                
                                VStack(alignment: .center) {

                                    Image("logo")
                                        .resizable()
                                        .frame(width: rowSection1.size.height/10 * 7, height: rowSection1.size.height/10 * 7, alignment: .center)
                                        
                                    Text("Haiku de Go")
                                        .font(.largeTitle)
                                        .fontWeight(.heavy)
                                        .foregroundColor(Color.white)
                                        
                                }.padding(.top, rowSection1.size.height/10 * 0.5)
                                .frame(maxWidth: .infinity, maxHeight: .infinity)

                            }
                            
                        }.frame(width: container.size.width, height: container.size.height/10 * 4, alignment: .center)
                        
                        // Email,password Section
                        VStack(alignment: .center) {
                            
                            Text("Log in to your account")
                                .font(.title)
                                .fontWeight(.bold)
                                .foregroundColor(self.color)
                            
                            TextField("Email", text: self.$email)
                                .padding()
                                .font(.title2)
                                .background(RoundedRectangle(cornerRadius: 4).stroke(self.email != "" ? Color("borderColor") : self.color, lineWidth: 2))
                                .background(Color.white)
                                .padding()
                            
                            HStack {
                                
                                VStack {
                                
                                    if self.visible {
                                        
                                        TextField("Password", text: self.$pass)
                                            .font(.title2)
                                    } else {
                                        
                                        SecureField("Password", text: self.$pass)
                                            .font(.title2)
                                    }
                                }
                                Button(action: {
                                    
                                }, label: {
                                    Image(systemName: self.visible ? "eye.slash.fill" : "eye.fill")
                                        .font(.title2)
                                        .foregroundColor(color)
                                })
                                
                            }
                            .padding()
                            .background(RoundedRectangle(cornerRadius: 4).stroke(self.pass != "" ? Color("borderColor") : self.color, lineWidth: 2))
                            .background(Color.white)
                            .padding()
                            
                            HStack {
                                
                                Spacer()
                                Button (action: {
                                    
                                }, label: {
                                    Text("Forget passward")
                                        .fontWeight(.bold)
                                        .foregroundColor(self.color)
                                })
                            }.padding()
                        }.frame(width: container.size.width, height: container.size.height/10 * 4, alignment: .center)
                        
                        // Login Button Section
                        VStack(alignment: .center) {
                            
                            Button (action: {
                                
                                // self.verify()
                            }, label: {
                                Text("Log in")
                                    .foregroundColor(color)
                                    .font(.title2)
                                    .fontWeight(.bold)
                                    .padding(.vertical)
                                    .frame(width: UIScreen.main.bounds.width - 200)
                            }).background(Color.white)
                            .cornerRadius(10)
                        }.frame(width: container.size.width, height: container.size.height/10, alignment: .center)
                    }
                }
            }
            
            // RegisterButton 右上に配置
            Button(action: {
                
            }, label: {
                Text("Register")
                    .fontWeight(.bold)
                    .foregroundColor(self.color)
            })
            .padding()
        }
    }
}
```

以上です。