LoginSignup
19
8

More than 1 year has passed since last update.

読みやすいpaddingを付けるコツ(SwiftUI)

Last updated at Posted at 2023-04-30

はじめに

SwiftUIで読みやすい padding を付けるコツを紹介します。

環境

  • OS:macOS Ventura 13.3.1
  • Xcode:14.3 (14E222b)
  • Swift:5.8

リファクタリング前のコード

以下のコードを読みやすくなるようリファクタリングします。

FooView.swift
import SwiftUI

struct FooView: View {
    var body: some View {
        VStack(spacing: 0) {
            Image(systemName: "swift")
                .resizable()
                .scaledToFit()
                .frame(width: 44, height: 44)
                .foregroundColor(.red)
                .padding([.leading, .trailing], 24)

            Text("This is Swift. Swift is very beautiful programming language.")
                .padding(EdgeInsets(top: 8, leading: 24, bottom: 32, trailing: 24))

            Image(systemName: "gear")
                .resizable()
                .scaledToFit()
                .frame(width: 44, height: 44)
                .foregroundColor(.gray)
                .padding([.leading, .trailing], 24)

            Text("This is gear.")
                .padding(.top, 8)
                .padding([.leading, .trailing], 24)
        }
    }
}

リファクタリング

.horizontal.vertical を使う

.leading.trailing をまとめて .horizontal で表せます。
同様に .top.bottom はまとめて .vertical と表せます。
記述が簡潔になるのでオススメです。

FooView.swift
import SwiftUI

struct FooView: View {
    var body: some View {
        VStack(spacing: 0) {
            Image(systemName: "swift")
                .resizable()
                .scaledToFit()
                .frame(width: 44, height: 44)
                .foregroundColor(.red)
-               .padding([.leading, .trailing], 24)
+               .padding(.horizontal, 24)

            Text("This is Swift. Swift is very beautiful programming language.")
                .padding(EdgeInsets(top: 8, leading: 24, bottom: 32, trailing: 24))

            Image(systemName: "gear")
                .resizable()
                .scaledToFit()
                .frame(width: 44, height: 44)
                .foregroundColor(.gray)
-               .padding([.leading, .trailing], 24)
+               .padding(.horizontal, 24)

            Text("This is gear.")
                .padding(.top, 8)
-               .padding([.leading, .trailing], 24)
+               .padding(.horizontal, 24)
        }
    }
}

今回は使っていませんが、上下左右の padding.all で表わせ、デフォルトは .all なので省略できます。
私は省略したほうが簡潔で読みやすいと思っています。

// 以下はすべて同義
// 下に行くほど読みやすいと思っている
.padding([.top, .leading, .bottom, .trailing], 24)
.padding(.all, 24)
.padding(24)

EdgeInset を使わない

EdgeInset を使うことで、1行で上下左右の padding を設定できます。
しかし4方向すべてを指定するイニシャライザしか存在せず、 .horizontal のようにまとめたり、 一部分のみ省略したりできません。
好みもありますが、私は EdgeInset を使わず .padding を複数付けて表現します。

FooView.swift
import SwiftUI

struct FooView: View {
    var body: some View {
        VStack(spacing: 0) {
            Image(systemName: "swift")
                .resizable()
                .scaledToFit()
                .frame(width: 44, height: 44)
                .foregroundColor(.red)
                .padding(.horizontal, 24)

            Text("This is Swift. Swift is very beautiful programming language.")
-               .padding(EdgeInsets(top: 8, leading: 24, bottom: 32, trailing: 24))
+               .padding(.top, 8)
+               .padding(.bottom, 32)
+               .padding(.horizontal, 24)

            Image(systemName: "gear")
                .resizable()
                .scaledToFit()
                .frame(width: 44, height: 44)
                .foregroundColor(.gray)
                .padding(.horizontal, 24)

            Text("This is gear.")
                .padding(.top, 8)
                .padding(.horizontal, 24)
        }
    }
}

要素同士の間隔には spacing を使う

こちらの記事 で説明している通り、一般的に padding は「親要素と子要素の間隔」を表します
SwiftUIで 「要素同士の間隔」は spacing で表す ので、そうなるように修正します。
VStackspacing0 にして、 padding で調整するのは望ましくありません。

VStackHStack はグルーピングの役割も果たします。
ImageText 間の spacing8swiftgear のグループ間の spacing32 とわかるので、 VStack(spacing:) を使って表現します。

FooView.swift
import SwiftUI

struct FooView: View {
    var body: some View {
-       VStack(spacing: 0) {
+       VStack(spacing: 32) {
+           VStack(spacing: 8) {
                Image(systemName: "swift")
                    .resizable()
                    .scaledToFit()
                    .frame(width: 44, height: 44)
                    .foregroundColor(.red)
                    .padding(.horizontal, 24)

                Text("This is Swift. Swift is very beautiful programming language.")
-               .padding(.top, 8)
-               .padding(.bottom, 32)
                .padding(.horizontal, 24)

+           VStack(spacing: 8) {
                Image(systemName: "gear")
                    .resizable()
                    .scaledToFit()
                    .frame(width: 44, height: 44)
                    .foregroundColor(.gray)
                    .padding(.horizontal, 24)

                Text("This is gear.")
-               .padding(.top, 8)
                .padding(.horizontal, 24)
        }
    }
}

グルーピングと spacing により、要素間の間隔が読みやすくなりました。

できる限り親Viewに巻き上げる

padding はできる限り親Viewに巻き上げて付けたほうが読みやすいです。
今回は行っていませんが、 Image + Text を部品化した際に、内部に padding があると外から値が確認しづらくなるためです。
また padding を内部に付けると部品を使い回しにくくなります。

今回は水平方向の padding がすべて 24 なので、まとめて一番外側の VStack に付けます。

FooView.swift
import SwiftUI

struct FooView: View {
    var body: some View {
        VStack(spacing: 32) {
            VStack(spacing: 8) {
                Image(systemName: "swift")
                    .resizable()
                    .scaledToFit()
                    .frame(width: 44, height: 44)
                    .foregroundColor(.red)
-                   .padding(.horizontal, 24)

                Text("This is Swift. Swift is very beautiful programming language.")
-                   .padding(.horizontal, 24)
            }

            VStack(spacing: 8) {
                Image(systemName: "gear")
                    .resizable()
                    .scaledToFit()
                    .frame(width: 44, height: 44)
                    .foregroundColor(.gray)
-                   .padding(.horizontal, 24)

                Text("This is gear.")
-                   .padding(.horizontal, 24)
            }
        }
+       .padding(.horizontal, 24)
    }
}

リファクタリング後のコード

リファクタリング後のコードです。
リファクタリング前より paddingspacing の使い分けができており、読みやすいと思います。

import SwiftUI

struct FooView: View {
    var body: some View {
        VStack(spacing: 32) {
            VStack(spacing: 8) {
                Image(systemName: "swift")
                    .resizable()
                    .scaledToFit()
                    .frame(width: 44, height: 44)
                    .foregroundColor(.red)

                Text("This is Swift. Swift is very beautiful programming language.")
            }

            VStack(spacing: 8) {
                Image(systemName: "gear")
                    .resizable()
                    .scaledToFit()
                    .frame(width: 44, height: 44)
                    .foregroundColor(.gray)

                Text("This is gear.")
            }
        }
        .padding(.horizontal, 24)
    }
}

最終的に padding の指定が1つのみとなり、本当に必要なのは「 FooView 全体に水平方向へ 24padding を設ける」とわかりました。

FooView を使い回す場合は内部から .padding(.horizontal, 24) を外し、呼び出し時に padding を付けます。

FooView()
    .padding(.horizontal, 24)

おまけ: paddingframe に影響する

padding を付けるとその分 frame が変わります。

border を付けるとわかりやすいです。

Before After
スクリーンショット 2023-04-30 23.39.57.png スクリーンショット 2023-04-30 23.38.45.png

要素間の間隔は frame に影響させたくないことが多いので、その意味でも今回のリファクタリングは有用です。
また frame が異なるのでリファクタリングと呼べるか怪しいですが、見た目は変わっていないため便宜上リファクタリングと呼んでいます。

逆に言えば、 frame を変えたい場合は padding を使う必要があります。

おわりに

読みやすい padding を付けるコツの紹介でした。
誤っている箇所やほかにコツがあれば、コメントなどで教えていただけると嬉しいです :relaxed:

参考リンク

19
8
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
19
8