Luis Ascorbe
Luis Ascorbe

Reputation: 2099

Setting the font of SwiftUI's .searchable() with the appearance API of UITextField+UISearchBar doesn't work

I'm customizing the appearance of the .searchable() modifier of SwiftUI with the appearance API of UISearchBar.

Almost everything works, except the font of the text field, and I have no idea why (setting the font of the cancel button works, or setting the background color or text color of the text field also work, so the correct reference is there).

Talk is cheap, show me the code!

let textAttributes: [NSAttributedString.Key: Any] = [
    .foregroundColor: UIColor.systemBlue,      // this works
    .font: UIFont.boldSystemFont(ofSize: 15)   // this doesnt
]
let placeholder = NSAttributedString(
    string: "Search...",                         // this doesnt
    attributes: [
        .foregroundColor: UIColor.systemGray,    // this works
        .font: UIFont.boldSystemFont(ofSize: 15) // this doesnt
])

let textFieldAppearance = UITextField
            .appearance(whenContainedInInstancesOf: [UISearchBar.self])
textFieldAppearance.backgroundColor = .red // this works
textFieldAppearance.defaultTextAttributes = textAttributes // color works, font not
textFieldAppearance.attributedPlaceholder = placeholder // color works, font or text not

I guess it's time to file a -radar- feedback?

Upvotes: 4

Views: 2032

Answers (3)

Toseef Khilji
Toseef Khilji

Reputation: 17419

I have do with UISearchTextField.appearance()

    let appearance = UISearchTextField.appearance()
    appearance.backgroundColor = .white.withAlphaComponent(0.15)
    appearance.tintColor = .white

    // Text attributes
    let attributes: [NSAttributedString.Key: Any] = [
        .foregroundColor: UIColor.white,
        .font: UIFont.boldSystemFont(ofSize: 15),
    ]
    appearance.defaultTextAttributes = attributes

    // Placeholder attributes
    let attributePlaceHolder: [NSAttributedString.Key: Any] = [
      .foregroundColor: UIColor.white.withAlphaComponent(0.5),
      .font: UIFont.boldSystemFont(ofSize: 15),
    ]
    
    appearance.attributedPlaceholder = NSAttributedString(string: "Search", attributes: attributePlaceHolder)

Addition to this we need to set font after .searchable

    .searchable(text: $viewModel.searchText,
                placement: .navigationBarDrawer(displayMode: .always),
                prompt: "Search")
     .font(.system(size: 14)) // This is also required

Because when the search bar is not active, it works fine, but when the SearchBarController is active, the font changes.

Upvotes: 0

JAHelia
JAHelia

Reputation: 7932

Setting the .font and .foregroundColor modifiers after .searchable will do the desired result, but it still doesn't work with .background modifier (if you want it) as the time of this writing (iOS 16).

Upvotes: -2

Luis Ascorbe
Luis Ascorbe

Reputation: 2099

I haven't found a reliable way of customizing this, with the solution posted below there's a glitch on the search bar that happens when SwiftUI re-renders the view (scrolling or just typing on the search bar), that is very obvious on a real device (not so much on the simulator).

Old answer:

Far from ideal, I found a way to make it work, which is introspecting the view searching for the UITextField and setting the font directly. The easiest way to do this is using a library like SwiftUI-Introspect (https://github.com/siteline/SwiftUI-Introspect).

Then on the View you're using .searchable() from just:

.introspectTextField { textField in
    textField.font = UIFont.boldSystemFont(ofSize: 15)
}

Fixed! The perfect solution would be to use the appearance API, but I guess we'll have to wait till iOS 16...

Upvotes: -2

Related Questions