The font modifier stores the Font in the environment for access by the modified views. You can read it and provide a default like this:
struct MyCustomTextField: View {
@Binding var text: String
@Environment(\.font)
var envFont: Font?
var body: some View {
HStack {
Image(systemName: "envelope").foregroundColor(.gray)
TextField("", text: $text)
.foregroundColor(.gray)
.font(envFont ?? .system(.title))
}
}
}
Unfortunately, the foregroundColor modifier doesn't store its setting in a (public) environment property, so you have to go a different route. One way is to provide a modifier directly on your custom view, like this:
struct MyCustomTextField: View {
@Binding var text: String
var _myColor: Color = .gray
@Environment(\.font)
var envFont: Font?
func myColor(_ color: Color) -> Self {
var copy = self
copy._myColor = color
return copy
}
var body: some View {
HStack {
Image(systemName: "envelope").foregroundColor(.gray)
TextField("", text: $text)
.foregroundColor(_myColor)
.font(envFont ?? .system(.title))
}
}
}
You can then use the myColor modifier directly on a MyCustomTextField like this:
PlaygroundPage.current.setLiveView(
MyCustomTextField(text: .constant("hello"))
.myColor(.red)
.padding()
.font(.body)
)
But you cannot use it on any enclosing view or after any non-MyCustomTextField-specific modifier. For example, this will not work:
PlaygroundPage.current.setLiveView(
MyCustomTextField(text: .constant("hello"))
.padding()
.myColor(.red) // Error: Value of type 'some View' has no member 'myColor'
.font(.body)
)
If you want that to work, then you need to store the custom color in the environment, like this:
struct MyColor: EnvironmentKey {
static var defaultValue: Color? { nil }
}
extension EnvironmentValues {
var myColor: Color? {
get { self[MyColor.self] }
set { self[MyColor.self] = newValue }
}
}
extension View {
func myColor(_ color: Color?) -> some View {
return self.environment(\.myColor, color)
}
}
struct MyCustomTextField: View {
@Binding var text: String
@Environment(\.myColor)
var envColor: Color?
@Environment(\.font)
var envFont: Font?
var body: some View {
HStack {
Image(systemName: "envelope").foregroundColor(.gray)
TextField("", text: $text)
.foregroundColor(envColor ?? .gray)
.font(envFont ?? .system(.title))
}
}
}
And then you can use the myColor modifier on any view, and it will apply to all enclosed subviews:
PlaygroundPage.current.setLiveView(
MyCustomTextField(text: .constant("hello"))
.padding()
.myColor(.red)
.font(.body)
)