nickcoding
nickcoding

Reputation: 475

Text() in front of TextField() blocking editing in SwiftUI

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)
            }
        }
    }
}

Upvotes: 1

Views: 1333

Answers (2)

Asperi
Asperi

Reputation: 257711

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))
    }
}

Upvotes: 2

user1046037
user1046037

Reputation: 17695

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)
        }
    }
}

Upvotes: 1

Related Questions