Reputation: 8493
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
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
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()
Upvotes: 4
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
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
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
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
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