After working with UIKit for quite a while I am now making my first steps in SwiftUI. In UIKit it is quite easy apply different themes to an app (e.g. as described here):
- Create different subclasses for controls which should have different styles. E.g.
class HeadlineLabel: UILabel {}
andclass BodyLabel: UILabel {}
- Define a
Theme
protocol which controls the different styling options like different fonts text sizes for the different label types. - Create a
ThemeManager
which applies the styles of the currentTheme
to the controls using the appearance proxy. E.g.HeadlineLabel.appearance().textColor = theme.headlineColor
The big advantage of this approach is, that in the rest of the code one has not think about theming at all. All one has to do, is to use the correct control subclasses (HeadlineLabel
, etc.) within the XIB or Storyboard files.
Is this also possible when working with SwiftUI?
Of course it is no problem to create and use a theme protocol when working with SwiftUI. However, since a SwiftUI view is a struct, one cannot create custom sub classes like struct HeadlineText: Text
or struct BodyText: Text
, simply because structs do not have inheritance...
So the only solution I found, is to apply the theming options to all controls manuall:
...
Text("Headline 1")
.foregroundColor(ThemeManager.currentTheme.headlineColor)
Text("Body 1")
.foregroundColor(ThemeManager.currentTheme.bodyColor)
Text("Headline 2")
.foregroundColor(ThemeManager.currentTheme.headlineColor)
Text("Body 2")
.foregroundColor(ThemeManager.currentTheme.bodyColor)
// Not possible
HeadlineText("Headline 3)
BodyText("Body 3")
Is this correct? Or is possible to apply styles to SwiftUI controls of a common type automatically?
CodePudding user response:
It's possible. You don't subclass Text
, you subclass View
to create a custom container:
struct HeadlineText: View {
var text: String
init(_ text: String) {
self.text = text
}
var body: some View {
Text(text)
//customize
}
}
HealineText("Hello")
Or you can create a custom ViewMofifier
:
struct HeadlineText: ViewModifier {
func body(content: Content) -> some View {
content
//customize
}
}
extension View {//or extend Text
func headlineText() -> some View {
return self
.modifier(HeadlineText)
}
}
Text("")
.headlineText()