7
4

More than 1 year has passed since last update.

LabelStyleの自作方法(SwiftUI)

Last updated at Posted at 2022-07-13

はじめに

Appleのサンプルコードを参考に、LabelStyleを自作する方法を紹介します。

環境

  • OS:macOS Monterey 12.4
  • Xcode:13.4.1 (13F100)
  • Swift:5.6.1

既存コードのリファクタリング

以下のコードをリファクタリングしながら、LabelStyleの実装を紹介します。

MonsterCellView.swift
HStack(spacing: 32) {
    Image(iconName) // var iconName: String
        .resizable()
        .scaledToFit()
        .frame(width: 68, height: 68)
    Text(name) // var name: String
        .font(.title)
        .frame(maxWidth: .infinity, alignment: .leading)
}
.padding(16)

LabelStyleを作成する

まずLabelStyleを実装します。

LabelStyle に準拠した構造体を作成し、 makeBody(configuration:) メソッドで既存コードの HStack をほぼそのまま返せばOKです。

変更点は以下です。

  • Image(iconName)configuration.iconText(name)configuration.title へ置き換える
  • Image に付いている .resizable() を外す
    • 理由はわからないが、付けるとビルドエラーになる
MonsterCellLabelStyle.swift
+ import SwiftUI
+ 
+ struct MonsterCellLabelStyle: LabelStyle {
+     func makeBody(configuration: Configuration) -> some View {
+         HStack(spacing: 32) {
+             configuration.icon
+                 .scaledToFit()
+                 .frame(width: 68, height: 68)
+             configuration.title
+                 .font(.title)
+                 .frame(maxWidth: .infinity, alignment: .leading)
+         }
+     }
+ }

LabelStyleのプレビューを作成する(任意)

必要に応じてLabelStyleのプレビューを作成します。

MonsterCellLabelStyle.swift
import SwiftUI

struct MonsterCellLabelStyle: LabelStyle {
    func makeBody(configuration: Configuration) -> some View {
        HStack(spacing: 32) {
            configuration.icon
                .scaledToFit()
                .frame(width: 68, height: 68)
            configuration.title
                .font(.title)
                .frame(maxWidth: .infinity, alignment: .leading)
        }
    }
}
+ 
+ struct MonsterCellLabelStyle_Previews: PreviewProvider {
+     static var previews: some View {
+         VStack {
+             Label {
+                 Text("uhooi")
+             } icon: {
+                 Image("uhooi")
+                     .resizable()
+             }
+             Label {
+                 Text("とてつもなく長い名前のモンスター")
+             } icon: {
+                 Image("uhooi")
+                     .resizable()
+             }
+         }
+         .labelStyle(MonsterCellLabelStyle())
+     }
+ }

Label の最初のクロージャーに Text 、 次のクロージャーに Image を渡します。
Image には先ほど外した .resizable() を付けます。

.labelStyle(MonsterCellLabelStyle()) でLabelStyleを適用します。

既存のViewをLabelに置き換える

LabelStyleを作成したら、既存のViewを Label に置き換えます。

MonsterCellView.swift
- HStack(spacing: 32) {
-     Image(iconName)
-         .resizable()
-         .scaledToFit()
-         .frame(width: 68, height: 68)
-     Text(name)
-         .font(.title)
-         .frame(maxWidth: .infinity, alignment: .leading)
+ Label {
+     Text(name)
+ } icon: {
+     Image(iconName)
+         .resizable()
}
+ .labelStyle(MonsterCellLabelStyle())
.padding(16)

これでLabelStyleの実装は完成です。

LabelStyleの指定をスマートにする(任意)

Appleのサンプルコードに面白いエクステンションがあったので、LabelStyleの指定をスマートにしたい場合に実装します。

MonsterCellLabelStyle.swift
import SwiftUI

struct MonsterCellLabelStyle: LabelStyle {
    func makeBody(configuration: Configuration) -> some View {
        HStack(spacing: 32) {
            configuration.icon
                .scaledToFit()
                .frame(width: 68, height: 68)
            configuration.title
                .font(.title)
                .frame(maxWidth: .infinity, alignment: .leading)
        }
    }
}

+ extension LabelStyle where Self == MonsterCellLabelStyle {
+     static var monsterCell: Self { .init() }
+ }
+ 
struct MonsterCellLabelStyle_Previews: PreviewProvider {
    static var previews: some View {
        VStack {
            Label {
                Text("uhooi")
            } icon: {
                Image("uhooi")
                    .resizable()
            }
            Label {
                Text("とてつもなく長い名前のモンスター")
            } icon: {
                Image("uhooi")
                    .resizable()
            }
        }
        .labelStyle(MonsterCellLabelStyle())
    }
}

このエクステンションにより、ドット始まりでLabelStyleを指定できるようになります。

MonsterCellView.swift
Label {
    Text(name)
} icon: {
    Image(iconName)
        .resizable()
}
- .labelStyle(MonsterCellLabelStyle())
+ .labelStyle(.monsterCell)
.padding(16)

Swiftっぽくなっていい感じです。

おわりに

これでLabelStyleを自作できるようになりました。
Labelを使うことで画像と文字列に関連があることを示せ、LabelStyleを使うことで構造と装飾を分離できます。

LabelとLabelStyleを使い、Viewの可読性を高めていきましょう :relaxed:

参考リンク

7
4
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
7
4