Custom animation for UISearchController?
Asked Answered
T

3

12

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.

Tiernan answered 17/1, 2018 at 15:13 Comment(8)
The App Store search has a similar transition, but in my case the initial text field is in the middle of the screen and not part of the navigation bar.Tiernan
do you have a gif or a video of the animation you're trying to achieve? I think you can use 2 different view controllers and navigate from one to another with the custom transition to make it look like it's still the same page (similar to the photos app)Pitapat
I added screenshots to the post for before and after (don’t know how to create a video of the animation in mind). However, it can be experienced in the iOS 11 App Store in the search tab.Tiernan
Maybe I am not good at reading but could you provide video how does your app behave?Fieldwork
@TruMan1, are you also planning to show a different table view when the search mode is activated (like the AppStore) or do you expect your search to filter the existing table?Pitapat
This may help. benmeline.com/search-bar-animation-with-swiftMonarchism
I've uploaded animated gif's and a sample app to illustrate what I'm hoping for.Tiernan
Did you try with adding textfield at the bottom of navigation bar.And when user tap textfield begineditng method it set the height of navigation bar to zero with animation and textfield will move up with same animation.Extempore
C
16

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.

Cacus answered 23/1, 2018 at 20:13 Comment(0)
O
3
  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()
      })
    }
    
Opportina answered 23/1, 2018 at 13:7 Comment(0)
O
2

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.

Otic answered 26/1, 2018 at 13:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.