Reputation: 1861
So far I am able to write custom modifiers for Views; however, when trying to keep my code DRY, I am trying to add a custom modifier for TextFields. The view modifiers work great with something like so:
struct sampleModifier : ViewModifier {
var height: CGFloat? = 100
func body(content: Content) -> some View {
content
.frame(height: height)
.background(Color.white)
.border(Color.gray, width: 0.5)
.shadow(color: Color.black, radius: 15, x: 0, y: 10)
}
}
But when I try to use modifiers like font
and so, it shows a lot of errors. I do understand that they might need to be more specific and instead conform to the TextFieldStyleModifier
, but I do not get how to make it work. I have tried to do it this way without success:
struct TitleModifier : TextFieldStyleModifier {
func body(content: TextFieldStyle) -> some View {
content
.font(.custom("Open Sans", size: 18))
.color(Color.green)
}
}
Which obviously fails and shows the following error:
If I click on the Fix
suggestion, it adds this to my code
TextFieldStyleModifier<<#Style: TextFieldStyle#>>
Which I do not know how to use.
Any suggestions?
Upvotes: 14
Views: 21191
Reputation: 21
// MARK: - Text Styles, iOS 15+:
import SwiftUI
struct TextStyle {
var fontFamily: String = "Roboto Flex"
let fontSize: CGFloat
let fontWeight: Font.Weight
let lineHeight: CGFloat
var lineSpacing: CGFloat { lineHeight - fontSize }
}
// MARK: - Create our styles:
extension TextStyle {
static let heading1 = TextStyle(
fontSize: 36,
fontWeight: .bold,
lineHeight: 44
)
static let heading2 = TextStyle(
fontSize: 30,
fontWeight: .medium,
lineHeight: 32
)
}
// MARK: - Create ViewModifier:
fileprivate struct TextStyleModifier: ViewModifier {
let textStyle: TextStyle
func body(content: Content) -> some View {
content
.font(
Font.custom(
textStyle.fontFamily,
size: textStyle.fontSize
)
.weight(textStyle.fontWeight)
)
.lineSpacing(textStyle.lineSpacing)
}
}
// MARK: - Create View extension:
extension View {
func setStyle(_ textStyle: TextStyle) -> some View {
modifier(TextStyleModifier(textStyle: textStyle))
}
}
// MARK: - Usage:
struct TestFont: View {
var body: some View {
VStack(alignment: .leading) {
Group {
Text("The quick brown fox jumps over the lazy dog and cat")
.setStyle(.heading1)
Text("The quick brown fox jumps over the lazy dog and cat")
.setStyle(.heading2)
}
.padding(10)
}
}
}
// MARK: - Preview:
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
TestFont()
}
}
Upvotes: 0
Reputation: 3498
As I know, use a Text extension is much better. For Text, some modifiers are very special, the return body type is not View, but Text. You can find many here.
extension Text {
func font(size: CGFloat) -> Text { // don't return `some View`
self.font(Font.custom("Open Sans", size: size))
}
}
This means we defined the type of Content and Body for ViewModifier, not sure there is a better way.
Upvotes: 5
Reputation: 133
Working with custom fonts:
add enum
, in a new file:
import SwiftUI
enum CustomFonts: String {
case bold = "Family-Bold", medium = "Family-Medium"
}
add extension, in a new file:
import SwiftUI
extension Font {
static func custom(_ font: CustomFonts, size: CGFloat) -> SwiftUI.Font {
SwiftUI.Font.custom(font.rawValue, size: size)
}
}
use:
Text("Hello World")
.font(.custom(.bold, size: 24))
Upvotes: 0
Reputation: 474
Right now it is possible to add .font()
and .foregroundColor()
modifiers to the content
inside ViewModifier. However, if you want to add some custom modifiers that can be applied only to a specific view, for example .strikethrough()
modifier for Text View, you can add these modifiers into the extension.
struct TitleModifier: ViewModifier {
func body(content: Content) -> some View {
content
.font(.custom("Open Sans", size: 18))
.foregroundColor(.green)
}
}
extension Text {
func customText() -> some View {
self.strikethrough().bold().italic().lineLimit(4)
.modifier(TitleModifier())
}
}
Usage Text("Hello").customText()
.
Upvotes: 24
Reputation: 2864
You can create a custom TextFieldStyle, this will apply only to TextField, not to other views on the view container
struct CustomTextFieldStyle: TextFieldStyle {
func _body(configuration: TextField<Self._Label>) -> some View {
configuration
.font(.custom("Open Sans", size: 18))
.foregroundColor(Color.green)
}
}
Usage:
Group {
Text("not applied here")
TextField("applied here", text: $presenter.name)
}
.textFieldStyle(CustomTextFieldStyle())
Upvotes: 5
Reputation: 9764
In Xcode 11 beta 4, the color(_:)
modifier is deprecated. So use the foregroundColor(_:)
method instead.
Upvotes: 1
Reputation: 40639
TextFields are also views, so you create the modifier in the same fashion:
struct TitleModifier : ViewModifier {
func body(content: Content) -> some View {
content
.font(.custom("Open Sans", size: 18))
.foregroundColor(Color.green)
}
}
Also note that there is no modifier .color(). It is .foregroundColor().
When you want to apply it to a FormField, you just do:
TextField("", text: $field1).modifier(TitleModifier())
Upvotes: 7