【SwiftUI】独自のStyleを定義してスタイリッシュなコードを書こう

この記事は KINTOテクノロジーズアドベントカレンダー2024 の11日目の記事です🎅🎄
メリークリスマス✌️🎅
KINTOテクノロジーズで my route(iOS) を開発しているRyommです。
本記事ではカスタムスタイルの紹介をします。
はじめに
私がこの書き方を知ったのはApp Dev Tutorialsがきっかけです。
なんてスタイリッシュなんだ…!
カスタムスタイルを使うことで、SwiftUIのコードが格段に読みやすく、洗練されたコードになる…!私もスタイリッシュなコードを書きたい!
そんな衝動に駆られて使い始めましたが、実際かなり便利で読みやすいのでおすすめです。
特に、用途別に乱立した構造体名を覚えていなくても ~~Style()
にドットで候補を探せるところが気に入っています。
カスタムスタイルのつくりかた
例えばLabelのカスタムスタイルを作成する場合、 LabelStyle
を継承した構造体を作成し、プロトコルに準拠したメソッド(ここでは makeBody(configuration:)
)内にスタイルを定義します。
configurationに含まれる値はものによって異なるので都度調べる必要がありますが、LabelStyleConfigurationに関してはTextとImageのViewが入っています。
/// 文字+アイコン のラベルスタイル
struct TrailingIconLabelStyle: LabelStyle {
func makeBody(configuration: Configuration) -> some View {
HStack {
configuration.title
configuration.icon
}
}
}
さらに LabelStyle
を拡張して、作成したカスタムスタイルを静的プロパティとして追加すると、呼び出し時に .labelStyle(.trailingIcon)
のように呼び出すことができて可読性が向上します。ン〜スタイリッシュ!
extension LabelStyle where Self == TrailingIconLabelStyle {
static var trailingIcon: Self { Self() }
}
もし「spaceを指定したい」など、引数を持たせたい場合はカスタムスタイルにメンバプロパティを追加することで実現できます。
/// 文字+アイコン のラベルスタイル
struct TrailingIconLabelStyle: LabelStyle {
// デフォルト値を設定しておくとドット始まりの呼び出し方法もキープできる
var spacing: CGFloat = 4
func makeBody(configuration: Configuration) -> some View {
HStack(spacing: spacing) {
configuration.title
configuration.icon
}
}
}
// 呼び出し
Label().labelStyle(.trailingIcon) // spaceにはデフォルト値が使われる
Label().labelStyle(TrailingIconLabelStyle(spacing: 2)) // spaceを2に指定
使いどころ
アプリ全体で広く使う共通デザインや、上記の TrailingIconLabelStyle
のように普遍的なカスタムスタイルに使うと良いでしょう。
たとえば、my routeではProgressViewで使っています。
ProgressView自体のスタイル設定もですが、ProgressViewを表示中に背景をグレーっぽくするのもスタイルに含めることができます。
struct CommonProgressViewStyle: ProgressViewStyle {
func makeBody(configuration: Configuration) -> some View {
ZStack {
ProgressView(configuration)
.tint(Color(.gray))
.controlSize(.large)
Color(.loadingBackground)
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
}
extension ProgressViewStyle where Self == CommonProgressViewStyle {
static var common: Self { Self() }
}
ちなみに、ProgressViewに background()
を指定するとProgressViewに必要なサイズのみしか描画されないので、ZStackでColorをProgressViewの下に敷き、背景色が与えられたサイズ全体に広がるようにしています。
このようにスタイルを作成することで、以下のように簡潔でスタイリッシュに書けるようになりました。
struct SomeView: View {
@State var loadingStatus: LoadingStatus
var body: some View {
SomeContentView
.overlay {
if loadingStatus == .loading {
ProgressView()
.progressViewStyle(.common)
}
}
.disabled(loadingStatus == .loading)
}
}
おわりに
カスタムスタイルの紹介でした!
以下のページにあるものはカスタムスタイルを作成できます。
よりスタイリッシュなコードを目指して一歩前進 🦌 🎄
関連記事 | Related Posts

【SwiftUI】独自のStyleを定義してスタイリッシュなコードを書こう

iOS App Design with Play

How We Built our Tech Blog Using Next.js
![Cover Image for [iOS] From UIKit + Combine to a Tailor-Made SwiftUI Architecture](/assets/common/thumbnail_default_×2.png)
[iOS] From UIKit + Combine to a Tailor-Made SwiftUI Architecture

When We Put Compose on Top of BottomSheetDialogFragment, Anchoring a Button to the Bottom Proved Harder Than Expected

Migrating to MapKit: A New Chapter for Unlimited App
We are hiring!
【UI/UXデザイナー】クリエイティブ室/東京・大阪
クリエイティブ室についてKINTOやトヨタが抱えている課題やサービスの状況に応じて、色々なプロジェクトが発生しそれにクリエイティブ力で応えるグループです。所属しているメンバーはそれぞれ異なる技術や経験を持っているので、クリエイティブの側面からサービスの改善案を出し、周りを巻き込みながらプロジェクトを進めています。
【クラウドエンジニア】Cloud Infrastructure G/東京・大阪
KINTO Tech BlogWantedlyストーリーCloud InfrastructureグループについてAWSを主としたクラウドインフラの設計、構築、運用を主に担当しています。