1

So I'd like my textfield to have a customizable placeholder text so I decided to put a Text() element in a ZStack in front of the text field. The only problem is, this Text() item blocks the selection of the textfield that is behind it (AKA when I click the placeholder I want the TextField to be clicked). Unfortunately, this Text() element blocks the click. I tried using the .allowsHitTesting() property as seen below but that also didn't work, and I'm not sure why.

struct ContentView: View {
    @State var text: String = ""

    var body: some View {
        ZStack {
            TextField("", text: self.$text)
                .background(Color.red)
                .foregroundColor(Color.white)
            if text.isEmpty {
                Text("Placeholder")
                    .allowsHitTesting(false)
            }
        }
    }
}
nickcoding
  • 305
  • 8
  • 35
  • TextField does provide an option to provide the place holder text. Are you trying to customise the placeholder text color? – user1046037 Aug 12 '20 at 02:37
  • @user1046037 Yep. I just made a minimum reproducible example for simplicity sake--but that is the reason I'm putting it in a Stack – nickcoding Aug 12 '20 at 02:38
  • Refer: https://stackoverflow.com/questions/57688242/swiftui-how-to-change-the-placeholder-color-of-the-textfield – user1046037 Aug 12 '20 at 02:40
  • @user1046037 I already saw that one--it won't help because I need the text field to have a background color...that background color blocks out the Text() element behind the TextField so the Text() element has to be in front of the textfield. Again, the only problem is it blocks the clickable area of the textfield. – nickcoding Aug 12 '20 at 02:47

2 Answers2

2

It can be done with custom text field style.

Here is a demo of solution (or parameters can be tuned). Tested with Xcode 12 / iOS 14 (border is just for visibility)

demo

struct PlaceholderStyle: TextFieldStyle {
    let isActive: Bool

    var placeholder = "Placeholder"
    var color = Color.white
    var backgrond = Color.red

    func _body(configuration: TextField<_Label>) -> some View {
        Text("\(isActive ? placeholder : "")")
            .foregroundColor(isActive ? color : .clear)
            .background(isActive ? backgrond : .clear)
            .frame(maxWidth: .infinity, alignment: .leading)
        .overlay(configuration)
    }
}

struct DemoView: View {
    @State private var text = ""
    var body: some View {
        TextField("", text: $text)
            .border(Color.gray).padding(.horizontal)
            .textFieldStyle(PlaceholderStyle(isActive: text.isEmpty))
    }
}
Asperi
  • 228,894
  • 20
  • 464
  • 690
1

See if this fits your needs:

struct ContentView: View {
    
    @State var text = ""
    
    var body: some View {
        ZStack(alignment: .leading) {
            if text.isEmpty { Text("Placeholder")
                .foregroundColor(.red)
                .background(Color.yellow)
            }
            TextField("", text: $text)
                .background(text.isEmpty ? Color.clear : Color.yellow)
        }
    }
}
user1046037
  • 16,755
  • 12
  • 92
  • 138