Sti
Sti

Reputation: 8493

How to center placeholder text in UISearchBar iOS 11

With iOS 11, searchBars are defaulting to a left aligned text. While this looks good with the rest of the native changes to iOS, it doesn't really fit my design, and I would like it to be center, as it was before.

I can't find any such alignment attributes on UISearchBar. Am I missing something, or is it simply not possible? Do I have to create my own custom search bar e.g derived from a UITextField to achieve this?

Upvotes: 14

Views: 14227

Answers (7)

msmq
msmq

Reputation: 1328

I did some modification in @Danny182 answer. Here is the updated version and it will work on all OS versions.

extension UISearchBar {
    func setPlaceHolder(text: String?) {
        self.layoutIfNeeded()
        self.placeholder = text
        var textFieldInsideSearchBar:UITextField?
        if #available(iOS 13.0, *) {
            textFieldInsideSearchBar = self.searchTextField
        } else {
            for view : UIView in (self.subviews[0]).subviews {
                if let textField = view as? UITextField {
                    textFieldInsideSearchBar = textField
                }
            }
        }
        
        //get the sizes
        let searchBarWidth = self.frame.width
        let placeholderIconWidth = textFieldInsideSearchBar?.leftView?.frame.width
        let placeHolderWidth = textFieldInsideSearchBar?.attributedPlaceholder?.size().width
        let offsetIconToPlaceholder: CGFloat = 8
        let placeHolderWithIcon = placeholderIconWidth! + offsetIconToPlaceholder
        
        let offset = UIOffset(horizontal: ((searchBarWidth / 2) - (placeHolderWidth! / 2) - placeHolderWithIcon), vertical: 0)
        self.setPositionAdjustment(offset, for: .search)
    }
}

You just need to call:

searchBar.setPlaceHolder(text: "Search \(name)")

Upvotes: 0

DanielZanchi
DanielZanchi

Reputation: 2768

This is the only one that worked for me, Swift 4.2:

extension UISearchBar {
func setCenteredPlaceHolder(){
    let textFieldInsideSearchBar = self.value(forKey: "searchField") as? UITextField

    //get the sizes
    let searchBarWidth = self.frame.width
    let placeholderIconWidth = textFieldInsideSearchBar?.leftView?.frame.width
    let placeHolderWidth = textFieldInsideSearchBar?.attributedPlaceholder?.size().width
    let offsetIconToPlaceholder: CGFloat = 8
    let placeHolderWithIcon = placeholderIconWidth! + offsetIconToPlaceholder

    let offset = UIOffset(horizontal: ((searchBarWidth / 2) - (placeHolderWidth! / 2) - placeHolderWithIcon), vertical: 0)
    self.setPositionAdjustment(offset, for: .search)
}
}


Usage:

searchBar.setCenteredPlaceHolder()

Result:
enter image description here

Upvotes: 4

SoftDesigner
SoftDesigner

Reputation: 5853

There's no official way to do that. Try using UISearchBarDelegate methods and your own UILabel.

extension YourViewController: UISearchBarDelegate {
    func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
        placeholderLabel.isHidden = true
    }

    func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
        placeholderLabel.isHidden = false
    }
}

Don't forget to hide the standard left-aligned icon (use blank image):

    searchBar.setImage(UIImage.imageWithColor(.clear), for: .search, state: .normal)

Upvotes: 1

rheligon
rheligon

Reputation: 1

For swift 4.0+

Well as your question doesn't really specify only placeholder I'll give an answer to both placeholder and the text. In my project, I needed both texts to be centered at all times, not just when I was not editing the textfield. You can return it to left align with some of the answers in this post by using the delegate as they stated.

Also im not using SearchController, but a SearchBar outlet, either way it can be easily fixed for your project if you use a controller. (just replace for searchController.searchBar instead of just searchBar).

So just have to call the next function where you need it.

func searchBarCenterInit(){
    if let searchBarTextField = searchBar.value(forKey: "searchField") as? UITextField {

        //Center search text
        searchBarTextField.textAlignment = .center

        //Center placeholder
        let width = searchBar.frame.width / 2 - (searchBarTextField.attributedPlaceholder?.size().width)!
        let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: width, height: searchBar.frame.height))
        searchBarTextField.leftView = paddingView
        searchBarTextField.leftViewMode = .unlessEditing
    }
}

Upvotes: 0

RJiryes
RJiryes

Reputation: 961

This is a bit of a workaround.

First of all you need to get the text field of the search bar and center the text alignment:

let textFieldOfSearchBar = searchController.searchBar.value(forKey: "searchField") as? UITextField textFieldOfSearchBar?.textAlignment = .center

After that, you need to change the placeholder's alignment. For some reason it doesn't change with the text field's alignment. You should do that by adding a padding to the left view of the textfield only when the search controller is active, so use it's delegate methods:

func presentSearchController(_ searchController: UISearchController) {
    //Is active
    let width: CGFloat = 100.0 //Calcualte a suitable width based on search bar width, screen size, etc..

    let textfieldOfSearchBar = searchController.searchBar.value(forKey: "searchField") as? UITextField

    let paddingView = UIView(x: 0, y: 0, w: width, h: searchController.searchBar.frame.size.height)
    textfieldOfSearchBar?.leftView = paddingView
    textfieldOfSearchBar?.leftViewMode = .unlessEditing
}

func willDismissSearchController(_ searchController: UISearchController) {
    let textfieldOfSearchBar = searchController.searchBar.value(forKey: "searchField") as? UITextField
    textfieldOfSearchBar?.leftView = nil
}

Good luck

Upvotes: 3

Ben
Ben

Reputation: 109

I had exactly the same problem - I'm struggling to understand why the default alignment would be changed without allowing us to easily set this back to centered.

The below works for me (Swift):

let placeholderWidth = 200 // Replace with whatever value works for your placeholder text
var offset = UIOffset()

override func viewDidLoad() {
    offset = UIOffset(horizontal: (searchBar.frame.width - placeholderWidth) / 2, vertical: 0)
    searchBar.setPositionAdjustment(offset, for: .search)
}

func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool {
    let noOffset = UIOffset(horizontal: 0, vertical: 0)
    searchBar.setPositionAdjustment(noOffset, for: .search)

    return true
}


func searchBarShouldEndEditing(_ searchBar: UISearchBar) -> Bool {
    searchBar.setPositionAdjustment(offset, for: .search)

    return true
}

Upvotes: 10

KVTaniguchi
KVTaniguchi

Reputation: 29

let placeHolderOffSet = UIOffset(horizontal: 100, vertical: 0) setPositionAdjustment(placeHolderOffSet, for: .search)

if you want a different position while the bar is active, you'll have to reset this in the corresponding delegate method

Upvotes: 0

Related Questions