Prajeet Shrestha
Prajeet Shrestha

Reputation: 8108

TextField customization for tvOS in SwiftUI

I wanted to customize looks of a TextField in tvOS but I can't seem to figure out way to alter default look of textfield when it's focused.

struct ContentView: View {
    @State var name: String = ""
    @State var address: String = ""
    var body: some View {
        VStack {
            TextField("Name", text: $name)
                .textFieldStyle(OutlinedTextFieldStyle())
            TextField("Address", text: $address)
        }
        
        .padding(200.0)
        .background(.white)
        .preferredColorScheme(.light)
    }
}

struct OutlinedTextFieldStyle: TextFieldStyle {
    @FocusState var isFocused: Bool
    func _body(configuration: TextField<Self._Label>) -> some View {
        configuration
            .focused($isFocused)
            .background(.clear)
            .overlay {
                RoundedRectangle(cornerRadius: 8, style: .continuous)
                    .stroke(.gray, lineWidth: isFocused ? 4 : 2)
            }
    }
}

This is the code I tried and here is the output:

Output

As you can see when I focus on the textfield by default TextField expands and shadow appears. I want to remove this effect and add some more customization when TextField is focused. How can I achieve that?

Upvotes: 1

Views: 46

Answers (1)

Mojtaba Hosseini
Mojtaba Hosseini

Reputation: 119858

This is related to the hoverEffect which is not much customizable in tvOS.

But here is a close try:

func _body(configuration: TextField<Self._Label>) -> some View {
    let shape = RoundedRectangle(cornerRadius: 8, style: .continuous)

    configuration
        .focused($isFocused)
        .defaultHoverEffect(nil) // 👈 Suppress the lifting effect
        .background(.clear)
        .padding(.horizontal, isFocused ? 16 : 0) // 👈 Suppress the padding effect 
        .overlay {
            shape.strokeBorder(.gray, lineWidth: isFocused ? 4 : 2)
        }
        .mask(shape) // 👈 Suppress the default shadow
}

Demo

Also, if you don't like the padding animation, you can:

  • pass nothing as the default placeholder
TextField("", text: $name)
    .textFieldStyle(OutlinedTextFieldStyle(placeholder: "Name", show: name.isEmpty))
  • make a custom placeholder and use it on top of the field
.overlay(alignment: .leading) {
    Text(placeholder)
        .padding()
        .foregroundStyle(.gray)
        .opacity(show ? 1 : 0)
    }

Note this is a work around and has side effects like loosing the title of the field in the edit screen and etc.

Upvotes: 1

Related Questions