UISearchBar presented by UISearchController in table header view animates too far when active
Asked Answered
M

15

58

I am using UISearchController to present a search bar inside the header view of a tableview:

...
self.searchController.hidesNavigationBarDuringPresentation = NO;            
self.presentingTVC.tableView.tableHeaderView = self.searchController.searchBar;
[self.searchController.searchBar sizeToFit];
self.presentingTVC.tableView.tableHeaderView = self.searchController.searchBar;

(where setting the tableHeaderView property twice is necessary as otherwise the header view overlaps the first row, c.f.a couple of answers on S.O. )

This is how it looks, perfectly in position when inactive: Inactive search bar in correct position

The search bar should just stay in place when active - I don't want it to move up to hide the navigation bar. But it unexpectedly animates down, leaving a blank space between it and the navigation bar:

Screenshot showing search bar animated too far down

Here's a video of weird search bar animation

If I just use a search bar separately from UISearchController, it does not show the same behaviour when it becomes active.

In my presenting view controller, I have self.definesPresentationContext = YES; and self.navigationController.navigationBar.translucent = YES;, and in IB none of the "extend edges" boxes are active (all seemed to be possible things that could throw search presentation off, from reading around).

Does anyone know how I can stop the search bar from animating down?

Microphotograph answered 4/2, 2015 at 16:20 Comment(4)
I'm having the same issue. I tried going through Apple's sample project here: developer.apple.com/library/ios/samplecode/… but still no luck. Will update if I find an answer.Carolincarolina
None of the solution worked for me: (Knowle
Your video link is now broken.Joeannjoed
Should be fixed now :)Illiterate
C
30

Ok so I finally figured out a solution for myself. Though it's more than likely we have other things in our code / storyboard (that's why this is a hard question to answer), for the most part I followed Apple's tutorial on UISearchController: (https://developer.apple.com/library/ios/samplecode/TableSearch_UISearchController/Introduction/Intro.html)

Just about all my code is identical to theirs, but I couldn't get the search bar to not jump when clicking inside of it. So what I did was check "under opaque bars" for both the original table view and the search results table view in my storyboard. That got the search bar to stop jumping.

But there was one last issue, which was the fact that the first row of the results table view was hidden by the search bar. In order to fix that I added self.tableView.contentInset = UIEdgeInsetsMake(kHeightOfTableViewCells, 0, 0, 0); to the viewDidLoad method of my results table view. Voila!

Carolincarolina answered 6/2, 2015 at 19:20 Comment(6)
It should be noted here that 'kHeightOfTableViewCells' is a constant I set in my table view class to define how tall my cells are.Carolincarolina
Yep I think that's getting somewhere! - see also https://mcmap.net/q/66324/-explaining-difference-between-automaticallyadjustsscrollviewinsets-extendedlayoutincludesopaquebars-edgesforextendedlayout-in-ios7Illiterate
Under opaque bars on the view controller in the storyboard did it for me, thanks!Russom
I had set my navigation bar as opaque recently and this got the bar jumping, what a crazy behavior!Drisko
Thanks! It helped. I wonder how did you get to that solution? Oh, how I love strange jumps or gaps in TableView which can be prevented by obscure boolean flags...Psychosis
To be honest I just experimented with every option I could think of and that one finally worked. This one was a bit of a head scratcher at the time.Carolincarolina
F
68

Old question but I was able to solve this issue by setting

self.extendedLayoutIncludesOpaqueBars = YES;

on my view controller. I think is issue is caused by having an opaque navigation bar but setting hidesNavigationBarDuringPresentation to NO on your search controller, causing the search bar to incorrectly position itself when focused.

Flounder answered 5/11, 2015 at 5:16 Comment(4)
public var extendedLayoutIncludesOpaqueBars: Bool // Defaults to NO, but bars are translucent by default on 7_0. So I really think Apple should by default set it to YES, since iOS7Bubbler
This works. Looks like the other solutions are a workaround.Industry
The combination of: self.definesPresentationContext = YES; and self.extendedLayoutIncludesOpaqueBars = YES; works for me.Assemblyman
Garanda's solution works for me too, the difference is I added this 2 in storyboard when read storyboard in xml. <viewController storyboardIdentifier="xxxVC" extendedLayoutIncludesOpaqueBars="YES" definesPresentationContext="YES" id="hgJ-Px-OtG" userLabel="xxxxViewController" customClass="xxxxViewController" .....Gynecic
C
30

Ok so I finally figured out a solution for myself. Though it's more than likely we have other things in our code / storyboard (that's why this is a hard question to answer), for the most part I followed Apple's tutorial on UISearchController: (https://developer.apple.com/library/ios/samplecode/TableSearch_UISearchController/Introduction/Intro.html)

Just about all my code is identical to theirs, but I couldn't get the search bar to not jump when clicking inside of it. So what I did was check "under opaque bars" for both the original table view and the search results table view in my storyboard. That got the search bar to stop jumping.

But there was one last issue, which was the fact that the first row of the results table view was hidden by the search bar. In order to fix that I added self.tableView.contentInset = UIEdgeInsetsMake(kHeightOfTableViewCells, 0, 0, 0); to the viewDidLoad method of my results table view. Voila!

Carolincarolina answered 6/2, 2015 at 19:20 Comment(6)
It should be noted here that 'kHeightOfTableViewCells' is a constant I set in my table view class to define how tall my cells are.Carolincarolina
Yep I think that's getting somewhere! - see also https://mcmap.net/q/66324/-explaining-difference-between-automaticallyadjustsscrollviewinsets-extendedlayoutincludesopaquebars-edgesforextendedlayout-in-ios7Illiterate
Under opaque bars on the view controller in the storyboard did it for me, thanks!Russom
I had set my navigation bar as opaque recently and this got the bar jumping, what a crazy behavior!Drisko
Thanks! It helped. I wonder how did you get to that solution? Oh, how I love strange jumps or gaps in TableView which can be prevented by obscure boolean flags...Psychosis
To be honest I just experimented with every option I could think of and that one finally worked. This one was a bit of a head scratcher at the time.Carolincarolina
R
28

I was able to prevent UISearchBar from shifting down by removing the following line from my ViewController: self.definesPresentationContext = YES;

Roentgenotherapy answered 8/4, 2015 at 9:20 Comment(2)
Fabulous answer. The idea is to make root view controller as the presenter of the search controller when there's multiple container VCs in the mix. By not setting, we are falling back to the root view controller resolved the insidious issues emanating from detached parent view controller(s). Thank you!Harrisonharrod
At first it worked. But later I noticed that I had a crash because of this fix: if I search and there are no results, tapping the button in the placeholder caused "no selector" type of crash - the button's segue wasn't working. Probably specifics of my setup, but be careful. The combination of self.definesPresentationContext = true and self.extendedLayoutIncludesOpaqueBars = true worked better for my setup.Pasteup
U
23

definesPresentationContext = true

override func viewDidLoad() {
        super.viewDidLoad()

        searchController = UISearchController(searchResultsController: nil)
        searchController.searchResultsUpdater = self
        searchController.hidesNavigationBarDuringPresentation = false

        searchController.dimsBackgroundDuringPresentation = true
        searchController.searchBar.searchBarStyle = UISearchBarStyle.Prominent
        self.tableView.tableHeaderView = searchController.searchBar

        definesPresentationContext = true
Unreflecting answered 10/12, 2015 at 3:28 Comment(2)
Me toooooo ! the definesPresentationContext = true is the life !Cilka
Worked for me! On other segue the controller was presenting fine, but on another stack it was disappearing. This fixed the issue on both.Orientalize
S
16

My turn. I also had this problem when I followed the WWDC sample code.

I noticed that if I didn't set the scopeButtonTitles property of the searchBar, the searchBar would not be visible. Upon closer inspection, it just had a frame of CGRectZero. This means that setting the scopeButtonTitles sets the frame behind the scenes. So If don't want to show any scopeButtonTitles, but still want to not have to hardcode UISearchBar to a specific height, set the scopeButtonTitles to an empty array.

self.searchController = UISearchController(searchResultsController: nil)
self.searchController.searchResultsUpdater = self
self.searchController.searchBar.scopeButtonTitles = []
self.tableView.tableHeaderView = self.searchController.searchBar

Setting the scopeButtonTitles to an array of 1 strings will not display the scope button titles, but still have logic to deal with the view, essentially screwing up the layout.

Props to Apple's QA team (applicable to iOS 8)

Sag answered 28/4, 2015 at 20:2 Comment(3)
Totally awesome. Works for my tableview with custom row layout on iOS 8!Flame
Setting an empty array for the scope definitely solves this problem on iOS8 when you're using a custom view controller and your own table / collection view.Sejm
You can also call sizeToFit to fix the zero-size problem.Predacious
K
15

I ran to this problem just recently and none of the solutions worked for me. Maybe because my UI is more complex (My table view with search supports in contained in UITabController inside a UiNavigationController) anyway, none of the above worker. I could simply solve my problem by this very neat piece of code I found at: UISearchController Not Redisplaying Navigation Bar on Rotate

- (UIBarPosition)positionForBar:(id<UIBarPositioning>)bar
{
    if (bar == searchController.searchBar) {
        return UIBarPositionTopAttached;
    }
    else { // Handle other cases
        return UIBarPositionAny;
    }
}

One more thing to add: after setting all my controller's hierarchy to extend under opaque and top bars, my search bar started to appear hidden under navigation bar and would've appeared right just after a rotation might happened. that was a cue for me that there is some lay out error and some information abut my layout was not right. this delegate method helps my controller understand the situation about the otherwise nomad search bar!

Kadiyevka answered 3/5, 2015 at 5:17 Comment(0)
M
6

Found it! This seems to be the offensive line in viewDidLoad of the presenting vc:

self.edgesForExtendedLayout = UIRectEdgeNone;

Removed that and the search bar stayed in place as predicted.

Microphotograph answered 5/2, 2015 at 23:42 Comment(4)
This didn't do it for me as I don't have this code in my project. I tried using another sample project: github.com/dempseyatgithub/Sample-UISearchController and breaking it down piece by piece but still no luck. Will keep searching.Carolincarolina
Hmm annoying! You can set the edgesForExtendedLayout on the view controller in the storyboard as well with the Extend Edges checkboxes. Maybe double check those?Illiterate
Also - I'm running into weird animations from the fact that UISearchController is now a fully fledged presented VC - so for example, I was seeing a weird dismissal animation where the search bar would fall to the bottom of the VC when Cancel was clicked. That was due to the presenting VC providing a transition context with a Vertical Transition type selected. All to say that perhaps if I understood a bit better how the presentation mechanisms are working, I might be able to debug all this weirdness more easily...!Illiterate
Thanks for the additional info. I'm messing around with the view controller check boxes on the storyboard. I fixed the scroll view jumping by checking "Under Opaque Bars" but now the first row of the table in the search controller is hidden by the search bar. Getting close ....Carolincarolina
C
4

unchecking Adjust Scroll View Insets

and

checking Under Top Bars

Fixed my problementer image description here

Clunk answered 27/2, 2017 at 10:0 Comment(1)
thanks man! after lots of digging, this is the only solution that worked for me . cheers!! you saved my dayAdlar
C
3

for iOS 11 & swift 4, set the line bellow in the viewController resolved my issue (searchBar jump down):

self.edgesForExtendedLayout = .bottom
Carefree answered 3/11, 2017 at 13:51 Comment(0)
P
1

I guess you set UISearchBar frame.original.y = 64

there are the code

if ([self respondsToSelector:@selector(setEdgesForExtendedLayout:)]) {
    [self setEdgesForExtendedLayout:UIRectEdgeNone];
}

searchBar.frame = CGRectMake(0, 0, 376, 44);

wash can help you

Plumose answered 6/5, 2016 at 2:33 Comment(0)
A
1

If you use UINavigationController and TabBar you can't use:

self.extendedLayoutIncludesOpaqueBars = true

You would need this solution: https://mcmap.net/q/331401/-uisearchcontroller-search-bar-overlap-first-cell-when-active

Alwitt answered 11/9, 2017 at 13:39 Comment(0)
M
1

Mine was the order of elements on the main controller .xib file.

This worked.

This worked

This didn't work.

enter image description here

Magaretmagas answered 20/1, 2020 at 2:51 Comment(0)
M
0

In my case, setting the nav bar to self.navigationController.navigationBar.translucent = NO; fixed the problem. It seems that the search bar presentation layer doesn't take into account the translucence of the nav bar when laying out the search bar.

I realize this isn't a perfect solution, because the translucence of the nav bar can throw off layout elsewhere, but it at least fixes the problem in the case where a non-translucent nav bar is a possibility.

Metameric answered 23/7, 2015 at 18:27 Comment(0)
T
0

As mentioned in the first post everyone needed a different solution. So here is mine. I had to combine two things mentioned on this page, namely:

Swift 2:

    navigationController?.navigationBar.translucent = true

    edgesForExtendedLayout = .None
Tribade answered 7/6, 2016 at 14:19 Comment(0)
S
0

its very simple just do clipsToBounds = true of header view of table view in witch search bar is added.

countryTableView.tableHeaderView?.clipsToBounds = true
Simultaneous answered 12/5, 2017 at 6:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.