Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom animation for UISearchController?

I'm presenting a UISearchController from my controller embedded in a navigation controller. The default animation occurs, where the search box drops down from the top on the navigation bar.

This isn't a good UX in my case because I present the search when a user taps into a UITextField in the middle of the screen. What I'd like to do is have the UITextField float to the top and morph into the search box, but I can't figure how to do this.

This is what I have:

class PlacesSearchController: UISearchController, UISearchBarDelegate {

    convenience init(delegate: PlacesAutocompleteViewControllerDelegate) {

        let tableViewController = PlacesAutocompleteContainer(
            delegate: delegate
        )

        self.init(searchResultsController: tableViewController)

        self.searchResultsUpdater = tableViewController
        self.hidesNavigationBarDuringPresentation = false
        self.definesPresentationContext = true
        self.searchBar.placeholder = searchBarPlaceholder
    }
}

private extension ShowAddressViewController {

    @objc func streetAddressTextFieldEditingDidBegin() {
        present(placesSearchController, animated: true, completion: nil)
    }
}

Instead of the search dropping down from the top, I'm hoping to get the text field fly up to the nav bar. What I’m after is the same effect that’s on the iOS 11 File app:

It has a text field in the middle of the screen then animated up to the navigation bar when you tap on it. In my case though, the text field is way lower in the screen and not originally part of the navigation bar.

like image 668
TruMan1 Avatar asked Jan 17 '18 15:01

TruMan1


3 Answers

UISearchController

UISearchController is a component that highly difficult to customize. From my experience I can say, that it is better to use it as is without any drastic or significant customization. Otherwise, customization could result in messy code, global state variables, runtime tricks with UIView hierarchy etc. If specific behavior still needed, it is better to implement search controller from scratch or use third party one.

Default implementation

Looks like UISearchController was designed to be used in couple with UITableView and UISearchBar installed in the table header view. Even apple official code samples and documentation provides such example of usage (see UISearchController). Attempt to install UISearchBar somewhere else often results in numerous ugly side effects with search bar frame, position, twitching animations, orientation changes etc.

Starting with iOS 11, UINavigationItem got searchController property. It allows to integrate search controller into your navigation interface, so search will look exactly like iOS Files or iOS AppStore app. UISearchController's behavior still coupled with another component, but I believe it is better than coupling with UITableView all the time.

Possible solutions

From my perspective there are several possible solutions for your problem. I will provide them in order of increasing effort, which is needed for implementation:

  1. If you still want to use UISearchController, consider to use it as is without significant customizations. Apple provides sample code, that demonstrates how to use UISearchController (see Table Search with UISearchController).
  2. There are several third party libraries which may be more flexible with lots of additional features. For example: YNSearch, PYSearch. Please, have a look.
  3. Along with UISearchController presentation, you could try to move UITextField up with changing alpha from 1 to 0. This will create a feeling that UITextField is smoothly transforming to UISearchBar. This approach described in article that was provided by Chris Slowik (see comment to your original post). The only thing I would improve is animations using transition coordinators (see example here), it will make animations smoother with synchronized timing. Final implementation also will be much cleaner.
  4. As an option, you could try to design your own search controller using only UISearchBar or even plain UITextField.
  5. You could subclass UISearchController and add UITextField object. UISearchController conforms to UIViewControllerAnimatedTransitioning and UIViewControllerTransitioningDelegate protocols, where UITextFiled could be removed or added along with transition animations.

I hope this helps.

Update:

I have implemented approach I described under point 3. Here is how it works:

UISearchController with UITextField

You can find code snippet here. Please note, that it is only code example, there are might be situations which are not handled. Check it twice then.

like image 150
Alex D. Avatar answered Sep 28 '22 19:09

Alex D.


  1. Create one UIView in XIB. name it searchView.
  2. Add UIButton inside above UIView in same xib and name it btnSearch. Like below in your scenario you have added textfield which is not mendetary

  3. Setup search controller in ViewDidLoad as below:

    func setupSearchController()  {
      self.searchController = UISearchController(searchResultsController: nil)
      self.searchController.delegate = self
      self.searchController.searchBar.delegate = self
      definesPresentationContext = true
      self.searchController.dimsBackgroundDuringPresentation = false
      self.searchController.searchBar.sizeToFit()
      searchView.addSubview(self.searchController.searchBar)
      self.searchController.searchBar.isHidden = true
      self.searchController.searchBar.tintColor = UIColor.white
      self.searchController.searchBar.showsCancelButton = false
      UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).tintColor = session?.makeColor(fromHexString: TYPE_COLOR, alpha: 1.0)
      self.searchController.searchBar.isTranslucent = false
      self.searchController.searchBar.barTintColor = UIColor(red: 239.0 / 255.0, green: 135.0 / 255.0, blue: 1.0 / 255.0, alpha: 1.0)
    }
    

    This method will setup searchcontroller programatically inside searchview.

  4. Now you just need to show searchcontroller programatically. add On click method of button in step 2. Call this below method name showsearchAnimation:

    func ShowSeachAnimation() {
      searchFrame = searchView.frame (add one global variable "searchFrame" in controller which saves searchView.frame so it will be used when cancel button clicked on search)
      self.btnSearch.isHidden = true        
      var yAxis : CGFloat = 20
      if #available(iOS 11 , *) {
         yAxis = 8
      } else  {
         yAxis = 20
      }
      searchView.translatesAutoresizingMaskIntoConstraints = true
      searchView.frame = CGRect(x: 0, y: yAxis, width: view.frame.size.width, height: view.frame.size.height - yAxis)
    
      self.searchController.searchBar.isHidden = false
      self.searchController.searchBar.becomeFirstResponder()
      self.searchController.searchBar.showsCancelButton = true
      self.searchBar(self.searchController.searchBar, textDidChange: "")
      searchView.layoutIfNeeded()
    }
    
  5. For hide searchbar, Add search hide method named "searchbarcancelbuttonclicked" in searchcontroller delegate:

    func searchViewHideAnimation()  {
      self.removeNavigationBar()
      self.navigationController?.isNavigationBarHidden = false
      self.searchController.searchBar.text = " "
      self.searchController.searchBar.isHidden = true
      UIView.animate(withDuration: 0.3, animations: {() -> Void in
          self.searchView.frame = self.searchFrame!
          self.btnSearch.isHidden = false
      }, completion: {(_ finished: Bool) -> Void in
          self.searchView.layoutIfNeeded()
      })
    }
    
like image 28
Code Hunterr Avatar answered Sep 25 '22 19:09

Code Hunterr


you can try to use my https://github.com/Blackjacx/SHSearchBar Which essentially will be your text field. You can add constraints to the left, right and top and adjust the top constraint when the text field editing begins. At the same time, you hide the navigation bar animated and gray out the background by using an overlay view. This way you have maximized control over your animations and this appüroach is not so difficult as it might sound.

like image 44
blackjacx Avatar answered Sep 25 '22 19:09

blackjacx