2

I am trying to create a Custom SearchBar so that I can

  1. Left Align the search image
  2. Change the corners of textbook to be a little more rounded.
  3. After the image is left aligned, the placeholder text can also be left aligned
  4. Change color of the search text

However, even after subclassing UISearchBar I am unable to achieve what I want and facing following problems:

  • When debugging, I can see UISearchBar in the view & searchField inside it, but upon iteration on self.subViews and checking if the element is UITextField, I don't get anything. Re-checked and I always get one subView which has different memory address than that of searchbar in debug mode

    var customSearchBar:UISearchBar?
    var searchField:UITextField?
    var button:UIButton?
    
    override func layoutSubviews() {
    for subView in self.subviews {
        if (subView.isKindOfClass(UITextField)) {
            searchField = (subView as! UITextField)
            break
        }
    }
    
    if ((searchField) != nil) {
        searchField?.textColor = UIColor.redColor() //Testing if code works?
    }
    
    super.layoutSubviews()
    }
    
  • I don't want to use undocumented ways and have almost tried all the ways I could find here, without any success

Kindly help me. I am using Xcode 7 and iOS 8

Sategroup
  • 955
  • 13
  • 29

2 Answers2

4

1.You can try this code:

let searchBar = UISearchBar(frame: CGRect(x: 0, y: 0, width: 300, height: 40))

searchBar.backgroundImage = UIImage()//Without this you can't change background color
searchBar.backgroundColor = UIColor.greenColor()

searchBar.showsCancelButton = true
searchBar.returnKeyType = .Done
searchBar.placeholder = "Test text"

var txtSearchField = searchBar.valueForKey("_searchField")
txtSearchField?.layer.cornerRadius = 15
txtSearchField?.layer.borderWidth = 1.5
txtSearchField?.layer.borderColor = UIColor.orangeColor().CGColor

let image = txtSearchField?.subviews?[1]
image?.frame = CGRect(x: 0, y: 7.5, width: 13, height: 13)

let lbl = txtSearchField?.subviews.last as! UILabel
lbl.textColor = UIColor.whiteColor()
lbl.backgroundColor = UIColor.blueColor()
lbl.frame = CGRect(x: 13, y: 1, width: 127.5, height: 25)

Result from Playground: enter image description here

  1. Also you can look at this and this open source solutions.
Alexey Bondarchuk
  • 2,002
  • 2
  • 20
  • 22
  • remove `searchBar.text = "GO"` and you will see the searchIcon and placeholder text is centered. However, I want both to left-aligned – Sategroup Aug 23 '15 at 17:05
  • @Sategroup Sorry, I've thought that this is easy to change frame for view. Check my update. – Alexey Bondarchuk Aug 23 '15 at 18:01
  • Again, you offer to use `valueForKey("_searchField")` which is a part of private API. If Apple changes the way it works - it will not behave as he expects. Better to use build-in customization, otherwise create own component. – gontovnik Aug 23 '15 at 20:38
  • @DanilGontovnik Then why it still works? :) Also I've provided 2 open source solutions written in swift or objective-c. – Alexey Bondarchuk Aug 23 '15 at 20:42
  • I do not say that it does not work, I just say that Apple may change that and it may stop working at any time. Open-source solutions are fine, I just told about using private methods and etc. ;) – gontovnik Aug 23 '15 at 21:28
  • @DanilGontovnik Agreed. And this is the simplest solution which do not require extra work e.g. custom searchBar. And yes, Apply may change this in future. But even in this case new changes will affect only new iOS version :) – Alexey Bondarchuk Aug 23 '15 at 22:05
  • So, the only way to avoid private API is to create your custom component? Does Apple rejects App when developers use such workarounds? – Sategroup Aug 24 '15 at 05:51
  • When you use private APIs Apple may reject, may not. Depends on how much of them you use and how they affect. I remember 2 years ago Apple did not allow to move status bar, however, now every second app moves Status Bar. Apple will never reject your app because of your custom components. :) – gontovnik Aug 24 '15 at 09:11
  • @Sategroup Apple not rejected my app. Thats why I've suggests this solution. – Alexey Bondarchuk Aug 24 '15 at 09:49
  • @Alexey, I would still refrain from using shortcuts 'subViews[1]` as it would cause problem in the future, though I am still facing problem accessing the search image. It's better to work on custom search bar, for which I shall post code as I get success. Thanks anyway... – Sategroup Aug 24 '15 at 13:59
  • @Sategroup This was quick approach how to get UIImageView. You can run `for` loop and check each view with `as!`. Even in case of changes you will get the same result without app crash. Also I've provided 2 open source solutions. You can reuse their work. – Alexey Bondarchuk Aug 24 '15 at 14:44
2

To understand logic of how UISearchBar is build you can have a look on their UISearchBar.h file with all private apis here. As you can see, it has UISearchBarTextField as a subview.

Last year in iOS 7 project I used this code to access UITextField of UISearchBar:

UITextField *searchBarTextField;    
for (UIView *subview in self.searchBar.subviews) {
    for (UIView *subsubview in subView.subviews){
    if ([subsubview isKindOfClass:[UITextField class]]) {
            searchBarTextField = (UITextField *)subsubview;
            break;
        }
    }
}

However, I would not recommend to use this logic, as if Apple changes private API method you UI and layout might be broken. You can try to use loop method to loop threw all subviews of subviews of UISearchBar and find needed text field, but again, it might be removed any time.

In the future, if you have any questions on how to access any subview on Apple build UI - you can debugger view hierarchy by pressing this button on debug panel:

enter image description here

If you want to make it custom - why not creating you own one? UIView + UITextField + UIButton + some logic = UISearchBar.

gontovnik
  • 690
  • 5
  • 9
  • Debugger hierarchy is just awesome. Thanks for that. I want to use a custom search bar only, that is why, I mentioned the same in the question. It's just that I don't know how to proceed further. Because, with the code you have provided, I can now get the `UITextField`, but still the search icon is not left aligned. Could you guide me on how to proceed further for creating custom search bar (UIView + UITextField + UIButton + some logic) – Sategroup Aug 23 '15 at 16:42
  • You create UIView, you add UITextField as a subview, you add UIButton as cancelation button (same as in native search bar). When user taps on UITextField search bar becomes active and cancelation button appears. When use press cancel - text field resigns first responder. And so and so and so on. Just have a look how native UISearchBar and UISearchDisplayControllers behave, use *Debug View Hierarchy* and try to replicate that. – gontovnik Aug 23 '15 at 20:42
  • the only problem with custom bar is I don't know where to start. When I call `self = super.initWithFrame(frame)`, I get an exception as this method doesn't return anything. Could you please help me with this as well? – Sategroup Aug 24 '15 at 05:49
  • What do you subclass? Could you please give more context of code. – gontovnik Aug 24 '15 at 15:40
  • I am subclassing UISearchBar. I will have to rewrite code as I deleted the previous one and thought of focusing on other tasks pending in my queue – Sategroup Aug 24 '15 at 15:43
  • [Here](https://artsy.github.io/blog/2012/05/11/on-making-it-personal--in-iOS-with-searchbars/) is a good example of subclassing UISearchBar. – gontovnik Aug 24 '15 at 15:44