Die Möglichkeit, benutzerdefinierte Ansichtsmodifikatoren zu erstellen, ist eine leistungsstarke Funktion in SwiftUI. In diesem Artikel werden wir Beispiele dafür behandeln, wie diese Funktion verwendet werden kann, um die Erstellung der Benutzeroberfläche erheblich zu vereinfachen. Wenn Sie mit ViewModifiers in SwiftUI und der Erstellung benutzerdefinierter ViewModifiers nicht vertraut sind, können Sie hier mehr darüber lesen
Ziel dieses Artikels ist es, einige der verschiedenen Möglichkeiten zum Erstellen benutzerdefinierter Modifikatoren und Stile in SwiftUI zu behandeln und zu erläutern, wie sie verwendet werden können, um die Benutzeroberfläche deklarativer zu gestalten und gleichzeitig eine saubere und konsistente Endausgabe zu erzielen.
Die endgültige Benutzeroberfläche, die wir erstellen möchten, ist diese:
Betrachten wir alle einzelnen Komponenten auf dem Bildschirm:
Wenn Sie diesen Bildschirm ohne Modifikatoren erstellen, würde der Code etwa so aussehen:
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) } }
Der Stil einiger Elemente (z. B. Titel- und Detailtexte) müsste dupliziert werden
Änderungen an einigen allgemeinen Stilen (Elementauffüllung, Eckenradius usw.) müssten an mehreren Stellen vorgenommen werden
Jetzt könnten Sie dieses Problem auf UIKit-Art lösen, indem Sie benutzerdefinierte Ansichten erstellen. Ich bin jedoch kein Fan dieses Ansatzes, da er die Abkehr von den integrierten Ansichten erfordert und das Onboarding neuer Teammitglieder reibungsloser macht. Eine einfachere Möglichkeit wäre, einige universelle Ansichtsmodifikatoren zu definieren, die anstelle der Stile selbst angewendet werden können.
Lassen Sie uns das allgemeine Styling, das wir benötigen, aufschlüsseln:
Beginnen wir mit dem Eckenradius:
struct CommonCornerRadius: ViewModifier { func body(content: Content) -> some View { content .cornerRadius(12) } }
Dies ist ziemlich einfach, es ermöglicht uns, einen universellen Eckenradius für Elemente anzuwenden. Dadurch ist es einfacher, App-Stile global zu ändern, ohne benutzerdefinierte Ansichten erstellen oder mehrere Änderungen in der gesamten Codebasis vornehmen zu müssen.
struct FullWidthModifier: ViewModifier { func body(content: Content) -> some View { content .frame(minWidth: 0, maxWidth: .infinity) } }
Dadurch ist die Implementierung von Ansichten in voller Breite einfacher, da kein .frame
mehr manuell hinzugefügt werden muss!
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)) } }
Dies ermöglicht eine allgemeine Textgestaltung. Normalerweise würden Sie entweder benutzerdefinierte Textkomponenten oder Dienstprogrammfunktionen erstellen und UI-Komponenten über Code hinzufügen.
extension Image { func aspectFill() -> some View { self .resizable() .aspectRatio(contentMode: .fill) } }
Okay, Sie haben mich verstanden ... das ist kein benutzerdefinierter Ansichtsmodifikator, sondern eine einfache Erweiterung. Dies liegt daran, dass ViewModifiers den generischen Ansichten ähneln und einige Funktionen wie resizable
nur für Bilder gelten. Die Verwendung einer Kombination aus Erweiterungen und benutzerdefinierten Modifikatoren hilft, dies zu umgehen.
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()) } }
Dies gilt schließlich für die Schaltfläche. Beachten Sie, dass wir zwar einfach einen ViewModifier hätten erstellen können, um den gleichen Effekt zu erzielen, das Erscheinungsbild der Schaltfläche sich jedoch beim Antippen nicht geändert hätte. Dies liegt daran, dass das Festlegen von .background
für eine Schaltfläche dazu führt, dass dieser Hintergrund sowohl im angetippten als auch im ungetippten Zustand verwendet wird. ButtonStyle
können wir die Deckkraft der Schaltfläche ändern, je nachdem, ob sie gedrückt wird oder nicht.
Der Einfachheit halber erstelle ich gerne Erweiterungen, die diese Modifikatoren verwenden:
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) } }
Viel sauberer! Auf den ersten Blick scheint dies mehr Code und Aufwand zu sein, als nur die Stile manuell festzulegen, aber auf lange Sicht wird dies eine Menge Aufwand sparen. Persönlich trägt dieser Ansatz auch dazu bei, dass der Stil Ihrer App konsistenter wird, indem mehr auf allgemeine Modifikatoren als auf eine Ansicht-für-Ansicht-basierte Gestaltung zurückgegriffen wird.
Und das war’s auch schon! Hoffentlich hilft Ihnen dies dabei, Ihre Apps schneller und einfacher zu erstellen. Ein weiterer Vorteil besteht darin, dass diese Modifikatoren in jede Ihrer Apps eingefügt und an deren Stilrichtlinien angepasst werden können. Ich habe auch an einer Bibliothek gearbeitet, um dies noch weiter voranzutreiben. Sie können sie sich hier ansehen (PS: Zum Zeitpunkt des Verfassens dieses Artikels befindet sich die Bibliothek in einem sehr frühen Stadium, das Repo ist leer :p, aber bleiben Sie dran)