SwiftUI. How to change the placeholder color of the TextField?
It's a bit modification for the @jfk's answer, we can create an extension for view
to simplify the modifier code inside the main view and also it can be used for Text
and Image
.
struct PlaceHolder<T: View>: ViewModifier {
var placeHolder: T
var show: Bool
func body(content: Content) -> some View {
ZStack(alignment: .leading) {
if show { placeHolder }
content
}
}
}
extension View {
func placeHolder<T:View>(_ holder: T, show: Bool) -> some View {
self.modifier(PlaceHolder(placeHolder:holder, show: show))
}
}
Usage in TextField:
Add this line of code .placeHolder(Text("Your placeholder"), show: text.isEmpty)
as a viewModifier
to TextField
.
TextField("", text: $text, onEditingChanged: { (changing) in
print("Changing: \(changing)")
}, onCommit: {
print("Committed!")
})
.placeHolder(Text("Your placeholder"), show: text.isEmpty)
Usage in Image:
Further more, as @EmilioPelaez suggested, I modified the code to support placeholder for any view for ex. Image
like below.
Image("your_image")
.placeHolder(Image("placeholder_image"), show: true)
There is no api for it (yet). BUT YOU CAN:
Use a custom placeholder
modifier to show any view as the holder of any other view! e.g:
TextField("", text: $text)
.placeholder(when: text.isEmpty) {
Text("Placeholder recreated").foregroundColor(.gray)
}
ð¡ It's a simple ZStack
that you can in a View
extension like:
extension View {
func placeholder<Content: View>(
when shouldShow: Bool,
alignment: Alignment = .leading,
@ViewBuilder placeholder: () -> Content) -> some View {
ZStack(alignment: alignment) {
placeholder().opacity(shouldShow ? 1 : 0)
self
}
}
}
ð Now you can apply any kind of style to the placeholder like this gradient placeholder with image:
✅ If you are interested, Here is how to apply resizable gradient on any view
ð¡ The Art of the simplicity
Most of the time you need to pass just a string and a gray placeholder like:
TextField("", text: $text)
.placeholder("Placeholder", when: text.isEmpty)
you can write a simple wrapper around the above extension for it:
extension View {
func placeholder(
_ text: String,
when shouldShow: Bool,
alignment: Alignment = .leading) -> some View {
placeholder(when: shouldShow, alignment: alignment) { Text(text).foregroundColor(.gray) }
}
}
Just like that ð
Eventually a ViewModifier that embeds the content in a ZStack is more elegant and less code:
public struct PlaceholderStyle: ViewModifier {
var showPlaceHolder: Bool
var placeholder: String
public func body(content: Content) -> some View {
ZStack(alignment: .leading) {
if showPlaceHolder {
Text(placeholder)
.padding(.horizontal, 15)
}
content
.foregroundColor(Color.white)
.padding(5.0)
}
}
}
Usage:
TextField("", text: $data)
.modifier(PlaceholderStyle(showPlaceHolder: data.isEmpty,
placeholder: "My Placeholder"))
On iOS 15, you can use prompt
public init(text: Binding<String>, prompt: Text? = nil, @ViewBuilder label: () -> Label)
Which works as a placeholder view