paint-brush
SwiftUI の基本ガイド: カスタム修飾子を使用した再利用可能な UI@nemi
1,615 測定値
1,615 測定値

SwiftUI の基本ガイド: カスタム修飾子を使用した再利用可能な UI

Nemi Shah9m2023/04/28
Read on Terminal Reader

長すぎる; 読むには

SwiftUI のカスタム ViewModifiers を使用すると、すべてのビューに適用できる再利用可能なスタイルを作成できます。この記事では、この機能を使用して UI の構築を非常に簡単にする方法の例を取り上げます。この記事の目的は、Swift UI でカスタム モディファイアとスタイルを作成するさまざまな方法のいくつかをカバーすることです。
featured image - SwiftUI の基本ガイド: カスタム修飾子を使用した再利用可能な UI
Nemi Shah HackerNoon profile picture
0-item
1-item

カスタム ビュー修飾子を作成する機能は、SwiftUI の強力な機能です。この記事では、この機能を使用して UI の構築を非常に簡単にする方法の例を取り上げます。 SwiftUIの ViewModifiers とカスタムのものを作成する方法に慣れていない場合は、ここでそれらについて読むことができます


この記事の目的は、SwiftUI でカスタム モディファイアとスタイルを作成するさまざまな方法と、それらを使用して UI をより宣言的に構築しながら、クリーンで一貫性のある最終出力を実現する方法について説明することです。


構築する最終的な UI は次のとおりです。


画面上の個々のコンポーネントをすべて考えてみましょう。

  • 画像: 角に半径がある標準的な画像コンポーネント
  • Texts: タイトルと本文があります
  • ボタン: 全角ボタン

プレーンな SwiftUI コード

この画面を修飾子なしで作成すると、コードは次のようになります。


 struct ContentView: View { var body: some View { VStack (alignment: .leading) { Image("feature") .resizable() .aspectRatio(contentMode: .fill) .frame(minWidth: 0, maxWidth: .infinity) .frame(height: 220) .cornerRadius(12) .padding(.bottom, 12) Text("Custom ViewModifiers in SwiftUI are the best!") .foregroundColor(Color("titleTextColor")) .font(.system(size: 20, weight: .bold)) .padding(.bottom, 12) Text("Custom ViewModifiers in SwiftUI let you create resuable styles that can be applied to all your views") .foregroundColor(Color("bodyTextColor")) .font(.system(size: 14, weight: .medium)) Spacer() Button(action: { }) { Text("Label") .font(.system(size: 14, weight: .medium)) } .frame(minWidth: 0, maxWidth: .infinity) .padding(.horizontal, 10) .padding(.vertical, 12) .background(Color.blue) .foregroundColor(Color.white) .cornerRadius(12) } .padding(.all, 16) } }


このアプローチにはいくつかの問題があります。

  • 一部の要素 (タイトルや詳細テキストなど) のスタイル設定を複製する必要があります。

  • 一般的なスタイリング (要素のパディング、角の半径など) の一部を変更するには、複数の場所で行う必要があります。


カスタムビューを作成することでUIKitの方法でこの問題を解決できますが、私はこのアプローチのファンではありません.もっと簡単な方法は、スタイル自体の代わりに適用できるいくつかのユニバーサル ビュー修飾子を定義することです。


必要な一般的なスタイリングを分解してみましょう。

  • 画面コンテナ: 画面自体にユニバーサル パディングがあります。これはオプションですが、すべての画面にユニバーサル スタイルを設定することをお勧めします。
  • コーナー半径
  • タイトルと本文
  • 全幅: 項目は親の幅を埋めることができる必要があります (上記の例のボタンと画像)
  • ボタンのスタイリング
  • 画像のスケーリング

カスタム ビュー修飾子

角の半径から始めましょう:

 struct CommonCornerRadius: ViewModifier { func body(content: Content) -> some View { content .cornerRadius(12) } }


これはかなり単純で、要素にユニバーサル コーナー半径を適用できます。これにより、カスタム ビューを作成したり、コードベース全体で複数の変更を行ったりすることなく、アプリ スタイルをグローバルに簡単に変更できます。


 struct FullWidthModifier: ViewModifier { func body(content: Content) -> some View { content .frame(minWidth: 0, maxWidth: .infinity) } }


これにより、全幅ビューの実装が簡単になり、手動で.frameを追加する必要がなくなります!


 struct TitleTextModifier: ViewModifier { func body(content: Content) -> some View { content .foregroundColor(Color("titleTextColor")) .font(.system(size: 20, weight: .bold)) } } struct BodyTextModifier: ViewModifier { func body(content: Content) -> some View { content .foregroundColor(Color("bodyTextColor")) .font(.system(size: 14, weight: .medium)) } }


これにより、一般的なテキスト スタイルが可能になります。通常は、カスタム テキスト コンポーネントまたはユーティリティ関数を作成し、コードを使用して UI コンポーネントを追加します。


 extension Image { func aspectFill() -> some View { self .resizable() .aspectRatio(contentMode: .fill) } }


わかりました。これはカスタム ビュー修飾子ではなく、単純な拡張機能です。これは、ViewModifiers がジェネリック ビューに適用され、 resizableなどの一部の機能が画像にのみ適用されるためです。拡張機能とカスタム修飾子を組み合わせて使用すると、これを回避できます。


 struct FullWidthButtonStyle: ButtonStyle { func makeBody(configuration: Configuration) -> some View { configuration.label .fullWidth() .foregroundColor(Color.white) .font(.system(size: 14, weight: .medium)) .padding(.horizontal, 10) .padding(.vertical, 12) .background(configuration.isPressed ? Color.blue.opacity(0.2) : Color.blue) } } struct FullWidthButton: ViewModifier { func body(content: Content) -> some View { content .buttonStyle(FullWidthButtonStyle()) } }


最後に、これはボタンの場合です。単純に ViewModifier を作成して同じ効果を実現することもできますが、タップしてもボタンの外観は変わらないことに注意してください。これは、ボタンに.backgroundを設定すると、タップされた状態とタップされていない状態の両方でその背景を使用するように強制されるためです。 ButtonStyleボタンが押されているかどうかに基づいてボタンの不透明度を変更できます。


便宜上、これらの修飾子を使用する拡張機能を作成するのが好きです。


 extension View { func commonCornerRadius() -> some View { modifier(CommonCornerRadius()) } func fullWidth() -> some View { modifier(FullWidthModifier()) } func title() -> some View { modifier(TitleTextModifier()) } func body() -> some View { modifier(BodyTextModifier()) } func fullWidthButton() -> some View { modifier(FullWidthButton()) } } extension Image { func aspectFill() -> some View { self .resizable() .aspectRatio(contentMode: .fill) } }


直接スタイリングする代わりに、これらを使用するようにコードを変換しましょう。


 struct ContentView: View { var body: some View { VStack (alignment: .leading) { Image("feature") .aspectFill() .fullWidth() .frame(height: 220) .commonCornerRadius() .padding(.bottom, 12) Text("Custom ViewModifiers in SwiftUI are the best!") .title() .padding(.bottom, 12) Text("Custom ViewModifiers in SwiftUI let you create resuable styles that can be applied to all your views") .body() Spacer() Button(action: { }) { Text("Awesome") } .fullWidthButton() .commonCornerRadius() } .padding(.all, 16) } }


もっときれいに!一見すると、スタイルを手動で設定するよりも多くのコードと労力がかかるように思えますが、長い目で見れば、これにより多くの労力が節約されます。個人的には、このアプローチは、ビューごとのスタイリングよりも共通の修飾子に依存することで、アプリのスタイルをより一貫性のあるものにすることも奨励します。


そしてそれはそれについてです!これにより、アプリをより迅速かつ簡単に構築できるようになることを願っています。もう 1 つの利点は、これらの修飾子を任意のアプリにドロップして、スタイル ガイドラインに合わせて微調整できることです。私はまた、これをさらに進めるためにライブラリに取り組んでいます。ここで確認できます (PS: これを書いている時点では、ライブラリは非常に初期の段階にあり、レポは空です :p ですが、お楽しみに)


こちらにも掲載。