I have a UINavigationController the root view controller of which is a UIViewController with a UICollectionView. The collection has constraint to the left, right, bottom and top. I've checked the prefersLargeTitles attribute in the UINavigationController, so I have big titles. I expected that, during the scroll, the UINavigationBar would automatically collapse, but I had to disable the large titles in my root view controller and add this line of code in my viewWillAppear :
navigationItem.largeTitleDisplayMode = .automatic
Then, I added also the search bar to the UINavigationBar, in this way :
let searchController = UISearchController.init(searchResultsController: nil)
searchController.searchResultsUpdater = self
navigationItem.searchController = searchController
Everything is perfect, visually.
Now, when I scroll down, the UICollectionView suddenly stick to the UINavigationBar which collapses. When I tap on the status bar to go to the top of the collection, a white space appears between the large title and the status bar. Is there a specific procedure that, for some reason, I'm not following? Do you have any solution?
EDIT:
Here you can find the video of the problem
When you see the collection that sticks to the UINavigationBar I confirm you that it's happening in a unnatural way. The last "bug" happens when I tap on the status bar.
Related
Here's Apple's document of scrollEdgeAppearance for UINavigationBar:
When a navigation controller contains a navigation bar and a scroll
view, part of the scroll view’s content appears underneath the
navigation bar. If the edge of the scrolled content reaches that bar,
UIKit applies the appearance settings in this property.
If the value of this property is nil, UIKit uses the settings found in the
standardAppearance property, modified to use a transparent background.
If no navigation controller manages your navigation bar, UIKit ignores
this property and uses the standard appearance of the navigation bar.
When running on apps that use iOS 14 or earlier, this property applies
to navigation bars with large titles. In iOS 15, this property applies
to all navigation bars.
Here's my demo. I embed ViewController into a UINavigationController, then drag a UITableView and set it as the subview of ViewController's view. I set the following appearance properties to UINavigationBar:
class ViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let redAppearance = UINavigationBarAppearance()
redAppearance.backgroundColor = .red
navigationController?.navigationBar.standardAppearance = redAppearance
let greenAppearance = UINavigationBarAppearance()
greenAppearance.backgroundColor = .green
navigationController?.navigationBar.scrollEdgeAppearance = greenAppearance
}
}
I thought the initial navigation bar should be red, and it should turn green when I scroll the table view. But the truth is it's the other way around.
I did some search and most people just set standardAppearance and scrollEdgeAppearance to the same instance, or set one of them to be nil, so I'm quite confused about these two properties in iOS 15.
You have understood perfectly but backward.
navigationController?.navigationBar.scrollEdgeAppearance = greenAppearance
means the nav bar will be green only when the scrollable view is scrolled all the way down. That is what you see in your first screen shot.
As soon as you scroll up a little bit, the nav bar starts adopting its standard appearance, which is red. That is what you see in your second screen shot.
scrollEdgeAppearance is applied when the edge of the scrollable content reaches the nav bar so what you're seeing is correct. Many people set both scrollEdgeAppearance and standardAppearance to the same since they want the behavior to be no different when the user scrolls but your implementation is certainly a valid use case.
Hi everyone I have a UITableViewController that hides the navigation bar when the user writes the tableView
navigationController? .hidesBarsOnSwipe = true
When the user shows the navigationBar by scrolling down the tableview, the navigationbar's slide animation appears to be delayed showing a black space between the tableView and the navigation bar
How can you solve this problem?
Here you can see what happens when the navigation bar is shown after the user scrolls down
Maybe you can try in viewDidLoad in your UITableViewController
self.edgesForExtendedLayout = []
Hope it will help you
Please help to determine the reason of such behavior (it's hard to describe by words, so I recorded the short video) https://youtu.be/E2ks0liFX4I
In short words:
Initially it's able to scroll content beneath navigation bar. If press search field - the search bar looks like detached from table view and goes too high and overlapped by status bar (look at increased space between grey border of search bar and first row in the table). After Cancel button pressed - the search bar jumps down and now can't be hided by scrolling.
I'm using UITableViewController.
Search bar initialization in viewDidLoad:
searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
tableView.tableHeaderView = searchController.searchBar
And in StoryBoard:
tableView settings
Not sure what u want. I guess u want the search bar to hide when scrolling?
I set searchbar to the navigationItem, then set the hidesSearchBarWhenScrolling property.
navigationItem.searchController = searchController
navigationItem.hidesSearchBarWhenScrolling = true
Edit: I tried adding in AppDelegate DidFinishLaunch..
let view: UIView = UIView.init(frame: CGRectMake(0, 0, UIScreen.mainScreen().bounds.size.width, 25))
view.backgroundColor = UIColor.redColor()
view.alpha = 1
self.window!.rootViewController!.view.addSubview(view)
After I changed the Status Bar to red, I prevented it going under status bar, but I realised that it wasn't just the Status Bar and there was something going on with the Navigation Bar while it gets swiped away. The content cells get shown until 1 seconds after NavBar gets swiped away. After 1 seconds, everything seem nice and no content cell gets over the header cell or status bar.
To clear up the problem, at the time Navigation Bar swipes away, there is a gap forms between Header Cell and status bar, so content cells appear for 1 seconds.
But how can I prevent this 1-2 second bug? It's the header cell that gives a gap for 1-2 seconds. It mostly occur if I swipe/roll the table view down fast.
I am leaving the original question below for the future readers.
Original Question:
I have a TableViewController that has Header & Content cells. I am hiding Navigation Controller on Swipe. However, after hiding Nav Bar, Content cells' content goes under the status bar at the top. Everything else is fine.
Header Cells seem fine, as they stop right below Status Bar.
Extend Edges - Top Bars should be checked for the header cell to stop going under status bar but unfortunately doesn't stop content cell.
I tried:
self.tableView.contentInset = UIEdgeInsetsMake(20, 0, 0, 0).
However, this gives a space between Header Cell & Status Bar (even before the Navigation Bar gets hidden). I want to achieve after hiding the Nav Bar.
self.extendedLayoutIncludesOpaqueBars = false does nothing.
self.automaticallyAdjustsScrollViewInsets = false Using this anchors the HeaderCell to the top of the view so HeaderCell gets positioned under NavigationBar.
self.edgesForExtendedLayout = UIRectEdge.None. Using this made the HeaderCell position itself starting from the top of Status Bar so half of the Header seems under status bar. (Also Navigation Bar - Bar Tint forces to become dull gray ignoring whatever I choose, so not really convenient)
I want to ask
Is there a way to not to make Status Bar opaque & make it solid? (I have the Status Bar - Inherred on Storyboard).
Otherwise, is there a way to prevent this behaviour? Maybe considering status bar solid; or maybe giving the Header Cell a space or position HeaderCell starting under the Status bar after the Navigation Bar gets hidden?
I had no luck getting it with TableViewController, here is my workaround...
Created a new ViewController
Unchecked 'Adjust Scroll View Insets'
Copied the TableView from TableViewController into ViewController's View.
Added constraints to TableView (Top/Bottom/Left -20/Right 20).
In AppDelegate, give white colour to Status Bar.
I'm trying to create a similar experience to the Contacts apps in iOS 8. The primary components of this are:
Keep the search bar fixed below the navigation bar
Have the search bar attach to the top of the view (standard functionality) when presenting.
This, however, is easier said than done. After a while of struggling with tableHeaderView (which didn't allow for interaction in front of the table view, and was complex with the viewDidLayoutSubviews positioning), I decided to embed a UITableView within a UIViewController, so I could add the UISearchBar as a subview. This worked pretty well, and allowed interaction with the search bar at all scroll positions, and the insets weren't hard to calculate.
But, the search bar gets cut off below the status bar, when activated. Seems like a straightforward issue—even if I didn't experience it with the exact same implementation in a UITableViewController. So, I tried making sure all my properties were set up for alignment, in every possible view controller.
self.edgesForExtendedLayout = UIRectEdgeNone;
self.extendedLayoutIncludesOpaqueBars = YES;
self.automaticallyAdjustsScrollViewInsets = NO;
I've tried every possible combination of these, in viewWillAppear as well as viewDidLoad, as well as translucent navigation bars and different starting frames for the table view and search bar. No luck. So, I tried to adjust the frames or constraints, perhaps using the topLayoutGuide or just 0. Unfortunately, adjusting the frame in any of the UISearchControllerDelegate methods didn't actually adjust its presented position, and adding constraints crashed immediately when the active animation begins (due to super.top not existing in the view hierarchy at the time; removing the constraints in willPresent did absolutely nothing).
After struggling for a bit longer, I tried implementing positionForBar as the UISearchBar's delegate:
- (UIBarPosition)positionForBar:(id <UIBarPositioning>)bar {
return UIBarPositionTopAttached;
}
This seemed to adjust the height, but the search bar flies off the top of the view. When activated, the search bar seems to appear directly above the visible area. This is even worse than it getting clipped behind or below the UIStatusBar. I also tried to just hide the status bar when the search controller becomes active, but conditionally implementing prefersStatusBarHidden didn't work at all (returning YES works great without UISearchController active, but when active it shows the status bar again or it gets shown beneath it). I assume this is because UISearchController refuses to obey any standards or rules, as is now painfully clear.
I've been trying to figure this out for a few days now, and I can't think of a solution besides reimplementing the UISearchController class/animation entirely. Please help!
For the behavior you described, this works great for me 😊
var resultSearchController = UISearchController()
And the following in your viewDidLoad function:
//Search Bar
self.resultSearchController = ({
let controller = UISearchController(searchResultsController: nil)
controller.searchResultsUpdater = self
controller.searchBar.sizeToFit()
controller.dimsBackgroundDuringPresentation = false
self.tableView.tableHeaderView = controller.searchBar
self.definesPresentationContext = true
return controller
})()
What worked for me was to subclass UISearchController and override the prefersStatusBarHidden in the subclass.
Also make sure View Controller Based Status Bar Appearance is set to YES
And in your viewcontroller containing the tableview / search bar:
self.definesPresentationContext = YES;
I have the same problem. I add a UISearchController to UIViewController,not using tableView.header. And the UISearchBar.superview.frame.origin.y is -44. So you cannot see the searchBar.
Method 1: You can change the frame of UISearchBarWrapperView in the didPresentSearchController,the delegate of UISearchControllerDelegate。But you will see the animation of this process.
Method 2: like JBlake say. Set self.definesPresentationContext = YES; after the UISearchController is init. It works!
What i understood is if u need searchbar under navigationbar as u mentioned in #1 its very easy just set a boolean (Solution for #1) searchController.hidesNavigationBarDuringPresentation = true
Unfortunately i couldnt fix the searchbar-offscreen-issue while navigationbar is hidden.