LoginSignup
1
0

【SwiftUI】 比率によるレスポンシブな配置を提案してみる

Last updated at Posted at 2024-03-29

こんにちは uni928 です。
今回は SwiftUI で
レスポンシブな配置を行う方法について
自己流の方法を提案してみたいと思います。

全ての要素を
比率で配置していく形式になります。

サンプルコードを載せて
その解説を行う形式で
紹介したいと思います。

それではよろしくお願いいたします。


今回は次のような見た目の
配置を目指したいと思います。

文字とボタン 6 個だけの
簡単な画面になります。

AutoLayoutQuestionScreenShot1.png


完成コード

完成コード
import SwiftUI

struct ContentView: View {
    
    var body: some View {
        GeometryReader { bodyView in
            getFirstView(bodyView.size.width, bodyView.size.height)
        }
    }
}

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

/**
 * 画面全体 View
 *
 * 9:19.5 をなるべく大きく切り取って
 * そこに getMainContent を配置
 */
func getFirstView(_ width: CGFloat, _ height: CGFloat) -> some View {
    
    //端末が 9:19.5 以上に縦長の場合
    if 19.5 / 9.0 <= height / width
    {
        let myWidth = width
        let myHeight = width * 19.5 / 9.0
        
        return AnyView (
            VStack(spacing: 0){
                
                //上の余白
                VStack(spacing: 0){}
                    .frame(width: width, height: ((height - myHeight) / 2))
                
                //メインコンテンツ
                getMainContent(myWidth, myHeight)
                    .frame(width: myWidth, height: myHeight)
                
                //下の余白
                VStack(spacing: 0){}
                    .frame(width: width, height: ((height - myHeight) / 2))
            }
            .frame(width: width, height: height)
        )
    }
    else
    {
        let myWidth = height / 19.5 * 9.0
        let myHeight = height
        
        return AnyView (
            HStack(spacing: 0) {
                
                //左の余白
                HStack(spacing: 0){}
                    .frame(width: ((width - myWidth) / 2), height: height)
                
                //メインコンテンツ
                getMainContent(myWidth, myHeight)
                    .frame(width: myWidth, height: myHeight)
                
                //右の余白
                HStack(spacing: 0){}
                    .frame(width: ((width - myWidth) / 2), height: height)
            }
            .frame(width: width, height: height)
        )
    }
}

/**
 * 画面比率 9:19.5 のメインの配置
 */
func getMainContent(_ width: CGFloat, _ height: CGFloat) -> some View {
    return VStack(spacing: 0) {
        
        //上の空間
        HStack{}
            .frame(width: width, height: (height / 12 * 4.2))
        
        //ボタンのある横1列
        getHorizontalLine(width, height / 12 * 2, 0)
        
        //ボタンとボタンの間の余白
        HStack{}
            .frame(width: width, height: (height / 12 * 0.6))
        
        //ボタンのある横1列
        getHorizontalLine(width, height / 12 * 2, 1)
        
        //ボタンとボタンの間の余白
        HStack{}
            .frame(width: width, height: (height / 12 * 0.6))
        
        //ボタンのある横1列
        getHorizontalLine(width, height / 12 * 2, 2)
        
        //下の空間
        HStack{}
            .frame(width: width, height: (height / 12 * 0.6))
    }
        .frame(width: width, height: height)
}

/**
 * 横1列
 */
func getHorizontalLine(_ width: CGFloat, _ height: CGFloat, _ lineID: Int) -> some View{
    return HStack(spacing: 0){
        
        //左の余白
        ZStack{}.frame(width: (width / 12 * 1.3), height: height)
        
        //左のボタン
        getButtonView(width / 12 * 4, height, lineID * 2)
        
        //ボタンとボタンの間の余白
        ZStack{}.frame(width: (width / 12 * 1.4), height: height)
        
        //右のボタン
        getButtonView(width / 12 * 4, height, lineID * 2 + 1)
        
        //右の余白
        ZStack{}.frame(width: (width / 12 * 1.3), height: height)
    }
        .frame(width: width, height: height)
}

/**
 * ボタン部分のView
 */
func getButtonView (_ width: CGFloat, _ height: CGFloat, _ buttonID: Int) -> some View {
    return Button(action: {buttonAction(buttonID)}){
        Text("button")
            .foregroundColor(Color.white)
            .font(.system(size: width / 5))
            .fontWeight(.bold)
    }
        .frame(width: width, height: height).background(.blue)
}

/**
 * ボタンの処理
 */
func buttonAction(_ buttonID: Int) {
    switch(buttonID){
    case 0:
        print("button0 が押されました")
    case 1:
        print("button1 が押されました")
    case 2:
        print("button2 が押されました")
    case 3:
        print("button3 が押されました")
    case 4:
        print("button4 が押されました")
    case 5:
        print("button5 が押されました")
    default:
        print("予期せぬボタンが押されました")
    }
}

getFirstView メソッドの中で
9:19.5 のレイアウトを配置しています。

AutoLayoutQuestionScreenShot2.png

getMainContent メソッドの中で
次の図のようにレイアウトを配置しています

AutoLayoutQuestionScreenShot3.png

getHorizontalLine メソッドの中で
次の図のようにレイアウトを配置しています。

AutoLayoutQuestionScreenShot4.png

これらの配置を行えば
後はボタンとテキストを
レイアウト上に配置するだけです。


以上が私個人的な
SwiftUI のレスポンシブな配置方法になります。
恐らく独自の方法ではないでしょうか?

複雑な配置も
この方法なら意外と簡単にできます。
是非お試しください。

この記事が
皆さんの開発の役に立てれば幸いです。

閲覧ありがとうございました。

1
0
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
1
0