13
votes

This is the searchbar that the designers want me to create

I need to make a custom search bar like this. The problem I am having is left aligning the placeholder text, as well as placing the search icon in the right. I have a png of the search icon that I have tried to use in an UIImageView, and set that UIImageView as the rightView of the UISearchBar's UITextField. This solution has not worked, and I ran out of ideas. Does anyone have a solution?

10
Not sure about the alignment of the text, but you might consider making the search icon into a custom UIButton, placed on top of the search bar, that functions as an "Enter" button. I've encountered a few apps that do that, and I've always enjoyed having the option of not having to tap the search field, bring up the keyboard, and hit "Search" from there if I want to re-run the search.Nerrolken
I've answered this on a different question. Happy to receive feedback on how to improve it: stackoverflow.com/a/25827025/3746156bdv

10 Answers

12
votes

Don't use a UISearchBar if you need to do these kinds of customizations. You'll have to make your own using a UITextField and a UIImageView, and responding to the delegate calls.

2
votes

Based in Mohittomar answer, as asked by @DevC to add spaces to the end of the place holder, here the code in swift:

I subclass placeholder in the UISearchBar, after set the value, I check if the last character is a space. then get the size of one space and how many spaces I need to add to align left.

class SearchBar: UISearchBar, UISearchBarDelegate {
override var placeholder:String? {
    didSet {
        if let text = placeholder {
            if text.last != " " {

// get the font attribute
                let attr = UITextField.s_appearanceWhenContainedIn(SearchBar).defaultTextAttributes
// define a max size
                let maxSize = CGSizeMake(UIScreen.mainScreen().bounds.size.width - 60, 40)
// get the size of the text
                var widthText = text.boundingRectWithSize( maxSize, options: .UsesLineFragmentOrigin, attributes:attr, context:nil).size.width
// get the size of one space
                var widthSpace = " ".boundingRectWithSize( maxSize, options: .UsesLineFragmentOrigin, attributes:attr, context:nil).size.width
                let spaces = floor((maxSize.width - widthText) / widthSpace)
// add the spaces
                let newText = text + (" " * spaces)
// apply the new text if nescessary
                if newText != text {
                    placeholder = newText
                }
            }
        }
    }
}
2
votes

A working solution for Drix answer

import Foundation
import UIKit

class LeftAlignedSearchBar: UISearchBar, UISearchBarDelegate {
    override var placeholder:String? {
        didSet {
            if #available(iOS 9.0, *) {
                if let text = placeholder {
                    if text.characters.last! != " " {
                        // get the font attribute
                        let attr = UITextField.appearanceWhenContainedInInstancesOfClasses([LeftAlignedSearchBar.self]).defaultTextAttributes
                        // define a max size
                        let maxSize = CGSizeMake(UIScreen.mainScreen().bounds.size.width - 87, 40)
//                        let maxSize = CGSizeMake(self.bounds.size.width - 92, 40)
                        // get the size of the text
                        let widthText = text.boundingRectWithSize( maxSize, options: .UsesLineFragmentOrigin, attributes:attr, context:nil).size.width
                        // get the size of one space
                        let widthSpace = " ".boundingRectWithSize( maxSize, options: .UsesLineFragmentOrigin, attributes:attr, context:nil).size.width
                        let spaces = floor((maxSize.width - widthText) / widthSpace)
                        // add the spaces
                        let newText = text + ((Array(count: Int(spaces), repeatedValue: " ").joinWithSeparator("")))
                        // apply the new text if nescessary
                        if newText != text {
                            placeholder = newText
                        }
                    }
                }
            }
        }
    }
}

This method appearanceWhenContainedInInstancesOfClasses is not available in iOS 8, there is a workaround for iOS 8 here

2
votes

SWIFT 3

swift 3 does not allow to override placeholder property. This is the modified version of Drix answer.

func setPlaceHolder(placeholder: String)-> String
   {

       var text = placeholder
           if text.characters.last! != " " {

               //                         define a max size

               let maxSize = CGSize(width: UIScreen.main.bounds.size.width - 97, height: 40)

               //                        let maxSize = CGSizeMake(self.bounds.size.width - 92, 40)
               // get the size of the text
               let widthText = text.boundingRect( with: maxSize, options: .usesLineFragmentOrigin, attributes:nil, context:nil).size.width
               // get the size of one space
               let widthSpace = " ".boundingRect( with: maxSize, options: .usesLineFragmentOrigin, attributes:nil, context:nil).size.width
               let spaces = floor((maxSize.width - widthText) / widthSpace)
               // add the spaces
               let newText = text + ((Array(repeating: " ", count: Int(spaces)).joined(separator: "")))
               // apply the new text if nescessary
               if newText != text {
                   return newText
               }

           }

       return placeholder;
   }

and call the function as :

searchBar.placeholder = self.setPlaceHolder(placeholder: "your placeholder text");
2
votes

A working swift 3 solution for Drix answer:

import Foundation
    import UIKit

    class LeftAlignedSearchBar: UISearchBar, UISearchBarDelegate {
        override var placeholder:String? {
            didSet {
                if #available(iOS 9.0, *) {

                    if let text = placeholder {
                        if text.characters.last! != " " {
                            // get the font attribute
                            let attr = UITextField.appearance(whenContainedInInstancesOf: [LeftAlignedSearchBar.self]).defaultTextAttributes
                            // define a max size
                            let maxSize = CGSize(width: UIScreen.main.bounds.size.width - 87, height: 40)
                            // let maxSize = CGSize(width:self.bounds.size.width - 92,height: 40)
                            // get the size of the text
                            let widthText = text.boundingRect( with: maxSize, options: .usesLineFragmentOrigin, attributes:attr, context:nil).size.width
                            // get the size of one space
                            let widthSpace = " ".boundingRect( with: maxSize, options: .usesLineFragmentOrigin, attributes:attr, context:nil).size.width
                            let spaces = floor((maxSize.width - widthText) / widthSpace)
                            // add the spaces
                            let newText = text + ((Array(repeating: " ", count: Int(spaces)).joined(separator: "")))
                            // apply the new text if nescessary
                            if newText != text {
                                placeholder = newText
                            }
                        }
                    }
                }
            }
        }

        /*
        // Only override draw() if you perform custom drawing.
        // An empty implementation adversely affects performance during animation.
        override func draw(_ rect: CGRect) {
            // Drawing code
        }
        */

    }
0
votes

If you want your control to respond exactly how you want, you should probably make your own custom control. This control could be separated in three parts :

  1. a background UIImageView
  2. a UITextField
  3. a UIButton for the the search icon if you want the user to interact with it

The easiest way to do that is probably to create a new class MySearchBar, with the three parts in the private interface :

@interface MySearchBar ()
@property (nonatomic, strong) UISearchBar* searchBar;
@property (nonatomic, strong) UITextField* textField;
@property (nonatomic, strong) UIButton* button;
@end

In your MySearchBar, you can create your component, customize it, add a better look & feel. To get back the search result, your control can have a delegate id<UISearchBarDelegate> (your UIViewController) which will basically simulate having a standard UISearchBar.

What remains is to create your MySearchBar in your controller and set the delegate to your view controller. The messages from the UISearchBarDelegate can either go to your MySearchBar to filter or do pre-treatment before sending to your UIViewController, or go directly to your UIViewController.

0
votes

No need to any customization just do it...

    searchBar.placeholder=@"Search                                                        ";

searchbar has centeral text alignment for its place-hoder , so just give some big text. and if you text is small then just use some space after place-holder text.

0
votes

Version for Xamarin

SearchBar.MovePlaceHolderLeft();

public static void MovePlaceHolderLeft(this UISearchBar  searchbar)
{
    NSAttributedString text = new NSAttributedString(searchbar.Placeholder ?? "");
    // define a max size
    var maxSize = new CGSize(width: UIScreen.MainScreen.Bounds.Size.Width - 97, height: 40);
    // get the size of the text
    var widthText = text.GetBoundingRect(maxSize, NSStringDrawingOptions.UsesLineFragmentOrigin, null).Size.Width;
    // get the size of one space
    var widthSpace = new NSAttributedString(" ").GetBoundingRect(maxSize, NSStringDrawingOptions.UsesLineFragmentOrigin, null).Size.Width;
    var spaces = Math.Floor((maxSize.Width - widthText) / widthSpace);
    // add the spaces
    string newText = searchbar.Placeholder;
    for (double i = 0; i < spaces; i++)
    {
        newText += " ";
    }
    searchbar.Placeholder = newText;
}
0
votes

it could be done from story board there is combo box with name semantic on attribute inspector of search bar if you set it to force right to left its done you have right align search bar and it has a similar thing for aligning from left

-2
votes

It's too late, but if anyone is still wondering the solution, then you can follow this.

UITextField *searchTextField = [searchBarController.searchBar valueForKey:@"_searchField"];

You can get the search field using above code. Now simply use the properties you want to use, like.

searchTextField.layer.cornerRadius = 10.0f;
searchTextField.textAlignment = NSTextAlignmentLeft;

PS. Text alignment property is used for text and placeholder both. Thanks.