iOS 11 UISearchController in Navigation Bar with UIRefreshControl causes layout glitch - uitableview

I am trying to use UIRefreshControl on a table view together with the new searchController API on navigationItem.
Now when I set hidesSearchBarWhenScrolling the "pull down to refresh" animation is not showing anymore and the refresh control just pops in at a certain point.
It appears to be a bug in UIKit (...same procedure as every year).
Did anyone find a solution for this one?
To reproduce the issue add this to a fresh iOS 11 "master/detail" sample project:
- (void)viewDidLoad {
// [setup code here]
self.refreshControl = [UIRefreshControl new];
self.navigationItem.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
self.navigationItem.hidesSearchBarWhenScrolling = NO; // <-- setting this causes jumpy UI
}

I just experienced the same problem. It definitely looks like a bug in UIKit. It would definitely be something filing a radar would be worth.
I found a very hacky way to mitigate it though:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
//Fixes a bug in UIKit where the refresh control is broken when `hidesSearchBarWhenScrolling` is NO.
if (#available(iOS 11.0, *)) {
self.navigationItem.hidesSearchBarWhenScrolling = scrollView.contentOffset.y < -scrollView.adjustedContentInset.top;
}
}
Basically what's happening here is that whenever the scroll view scrolls past the top (where the refresh control would become visible), this bit of code will turn hidesSearchBarWhenScrolling back to YES. Once the user scrolls back down again, it will be set back to NO and the search bar will continue to remain visible.
Hopefully Apple will fix this in a future iOS version, but for current shipping versions, this will probably have to do.

Related

UIControl tracking and iOS 13 presentation style cards not working together

I am using AORangeSlider which is a subclass of UIControl that overrides the beginTracking, continueTracking and endTracking methods.
When this control is added to a viewController, which is presented in iOS 13 using the "cards style", it has very strange behavior. When sliding the control the viewController will try to swipe down, and it interrupts the slider behavior and makes it unreliable and not work correctly.
If I instead, I present the viewController with UIModalPresentationFullScreen the control works correctly.
Is there a way to allow the AORangeSlider/UIControl to work with the iOS 13 cards style of presentation and not have their touch events conflict?
Had to ask Apple about this, and they recommended the following solution, which worked:
if (#available(iOS 13.0, *)) {
for (UIGestureRecognizer *gestureRecognizer in self.navigationController.presentationController.presentedView.gestureRecognizers) {
gestureRecognizer.enabled = NO;
}
}

Responding to navigation bar height changes during push transition

In iOS 11 the search bar will now change the navigation bar height to 56dp when adding a search bar to the navigationItem.titleView
I like the height change and don't intend on forcing the height to stay at 44dp or lower.
unfortunately when transitioning from one view controller to another the pushed view will be drawn with the larger navigation bar in mind and then the bar height is changed after the transition is finished.
That looks a little like this:
I need a way of getting the navigation controller to recognise the height change during the transition so that it can animate to the smaller size and draw the view correctly.
I have one current fix which I don't like because it's a little jumpy and it's more work the app has to do and also it has to re-evaulate it's views regardless of which view controller it's being pushed from.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if #available(iOS 11, *) {
navigationController?.view.layoutSubviews()
}
}
So far I haven't found any similar questions on stack overflow, any comments from WWDC and nothing in the official apple documentation.
I've seen many apps deal with this however. The apple contacts app will create what looks like two navigation bars and will move between them without animating the height changes and the fb messenger app will perfectly transition between the heights and even allow for the interactive pop transition.
Using this one, it will keep your searchbar's height fixed
if #available(iOS 11.0, *) {
searchBar.heightAnchor.constraint(equalToConstant: 44.0).isActive = true
}
I tried a lot of different functions.
This thing is the only one that really helps
OBJ C:
if (#available(iOS 11, *)) {
self.navigationController.view.layoutSubviews;
}
SWIFT:
if #available(iOS 11, *) {
self.navigationController.view.layoutSubviews()
}

Hide large title when scrolling up

I have a normal view controller that is embedded in a navigation controller. In this view controller, I have a table view that is using the constraints of the safe area. (I don't use a table view controller)
The navigation controller is set to prefer large titles and the mode is set to .always. In beta 2 this worked perfectly, So when I came in the title was large and when I scrolled down it became small (Like the normal one). But since beta 3 this doesn't work anymore.
Anyone know how to turn this back on, or how to make it so when I scroll the table view it will become smaller. Like the behaviour of all the new iOS 11 apps?
Or is this a bug in the current version of swift 4/iOS 11 but the apps like messenger and settings still work this way.
Thanks in advance.
For me, it was that if you set the boolean "Prefers Large Titles" in the storyboard to true it will stay large, if you turn this on by code it works as expected!
I found a workaround on this site
basically, if the tableView (or element that has scroll)is not the first view in your view hierarchy, the large title fails to hide automatically.
https://markusbodner.com/2017/10/08/fix-large-navigation-bar-title-not-hiding-on-scroll-in-ios-11/
I added on the view willAppear:
if #available(iOS 11.0, *) {
navigationController?.navigationBar.prefersLargeTitles = true
} else {
// Fallback on earlier versions
}
(void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (scrollView.contentOffset.y > 0) { //20
[self.navigationController.navigationBar setPrefersLargeTitles:NO];
} else {
[self.navigationController.navigationBar setPrefersLargeTitles:YES];
}
}
Check "Prefers Large Titles" for your navigation bar in IB, or use:
navigationController?.navigationBar.prefersLargeTitles = true
I'm using a programmatic layout and ran into a similar issue with large titles. I found the solution here: https://stackoverflow.com/a/46692583/131378. In viewDidLoad() I had to toggle the largeTitleDisplayMode off and on again. That was the correct combination that got the large titles working with scrolling:
self.navigationItem.largeTitleDisplayMode = .never
self.navigationItem.largeTitleDisplayMode = .always

UISearchbar vanishes when in UIScrollView

I seem to be having an issue with the UISearchbar in iOS 7 vanishing in two scenarios. First the controller is fairly simple it has a nib which contains a scrollview which has in it the uisearch bar and some content. The ui search bar is at the top of the scrollview. So when I scroll the scrollview so the uisearchbar is longer visible and I exit and reneter the controller the uisearch bar is longer visible. Clicking the region makes it appear again. The uisearchbar also vanishes when I double tap it quickly. This controller worked fine is iOS 6 these issues are only happening now that I am building for ios 7
Edit
Investigating the double tap issue causing the uisearchbar to disappear. It seems that the uisearch bar when double tapped quickly is removing the uisearchbar from the view hierarchy when displaying it but never readding it back when it has been dismissed. So I can workaround that by doing
- (void)searchDisplayControllerDidEndSearch:(UISearchDisplayController *)controller
{
// workaround for bug in ios 7 were quickly double tapping uisearchbar (e.g it appears and get dismissed quickly)
// does not re add the uisearch bar to the correct view.
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"7.0")) {
UIView *parentView = [self.scrollView.subviews objectAtIndex:0];
[parentView addSubview:self.searchDisplayController.searchBar];
}
return;
}
Have you tried doing some UI refresh stuff?
Like:
- (void)viewWillAppear:(BOOL)animated{
[self.scrollView setNeedsLayout];
}

UISearchBar with statusbar animation transition bug ios7

I have a problem with UISearchBar animation.
The animation is buggy when the statusbar is on. Otherwise it is okay.
I created the tableview and the searchbar programatically. The uisearchbar is in the headerview of a tableview. It's important that it stays that way. I know its working okay when you use the storyboard.
I created a very basic sample project as I think this is the easiest way to show you the problem.
I have spent several hours to find the solution but I just can't figure it out. Any help would be greatly appreciated.
Here's a link to the sample project: SearchBarProject!
I found that
self.navigationController.navigationBar.translucent = YES;
made my animation less buggy
I thinks this is IOS 7 bug. There is an uitableview search example application provided by Apple. And it has same problem while finishing editing search bar. With IOS 6 there is no any problem
Just add a sublayer to the UISearchBar and change the view's background color will make the animation almost perfect
- (void) searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller {
self.view.backgroundColor = RGB(199,199,204);
self.fixSearchAnimation = [[UIView alloc] initWithFrame:CGRectMake(0, -20,320, 40)];
self.fixSearchAnimation.backgroundColor = RGB(199,199,204);
[self.searchController.searchBar addSubview:self.fixSearchAnimation];
[self.searchController.searchBar sendSubviewToBack:self.fixSearchAnimation];
}
- (void) searchDisplayControllerDidEndSearch:(UISearchDisplayController *)controller {
self.view.backgroundColor = [UIColor whiteColor];
[self.fixSearchAnimation removeFromSuperview];
}
in slow mode, you can still see a tiny line between the searchbar origin subviews and the new view, but it's not very noticeable for a user, and if that disturb you, you can dig into the view hierarchical of UISearchbar and put the view in the right position.

Resources