I have a UICollectionView that I want to go under the navigation bar. Basically I want it to ignore the entire top safe area, yet still want it to respect the bottom safe area, as there's a tabbar there. This is how it currently looks:
But I want the first cell to start directly the very top of the screen, under the (translucent) navigation bar and the status bar.
If I set collectionView.contentInsetAdjustmentBehavior = .never, then the top part works great, but then the bottom part of the collection view content is hidden by the tabbar - you can't scroll all the way to the bottom so to speak. So I have to manually add a bottom inset again? How do I get the height of the tabbar, including any bottom safe area on devices that have the home bar? Or is there a better way to tell the collectionview to ignore only the top area for its content inset adjustment?
You just need to set the bottom content inset of the collection view manually, after setting the adjustment behavior to .never.
The correct inset (including the tab bar and any home bar) can be found in safeAreaInsets.
collectionView.contentInsetAdjustmentBehavior = .never
collectionView.contentInset.bottom = collectionView.safeAreaInsets.bottom
You'll need to do this at a point when the safeAreaInsets have been set, such as viewDidLayoutSubviews.
As far as I remember, it used to be possible by simply adjusting the edgesForExtendedLayout property of the containing view controller, but that was phased out when safe areas were introduced in iOS 11 I believe.
Related
I am trying to design a side menu, whose height would be equal to screen height (therefore hiding the navigation bar too). However I am unable to get the same.
I have put constraints as this:
and in viewDidLayoutSubviews()
I have mentioned - sideMenuTopConstraint.constant = -1 * (self.navigationController?.navigationBar.frame.height)!
However I see no change. Also by increasing the height of the side menu view in storyboard, I see that it is always below the nav bar. How do I make it appear above it?
You need to add the view to window as a subview, that should bring this view above the navigation bar as needed.
This is because window is the root of all the views.
UIApplication.sharedApplication().keyWindow?.addSubview(desiredViewHere)
In my iOS app, I have views rendered beneath the navigation bar. This is because the navigation bar is hidden until the user taps the screen.
The screenshots below illustrate my problem.
The "X" button is rendered beneath the iPhone X's notch and can hardly be seen. This is when I constrain the button's topAnchor to its superview!.topAnchor.
Note that this works as intended for all devices except the iPhone X.
The "X" button in this screenshot is anchored to its superview!.safeAreaLayoutGuide.topAnchor and renders below the navigation bar. This makes sense given Apple's documentation on safeAreaLayoutGuide:
"this guide reflects the portion of the view that is not covered by navigation bars, tab bars, toolbars, and other ancestor views."
However, I want the "X" button to render below the iPhone X's notch and underneath the navigation bar. Here's what it looks like when the navigation bar is hidden:
The "X" button should render right below the notch.
So my question is:
Is there a way to exclude the navigation bar from a view's safeAreaLayoutGuide? And if not, what are my options, other than manually offsetting the button on iPhone X's.
Note that I'm doing everything programmatically. I no longer use Storyboards.
Thanks!
You can change the view controllers safe area insets by adding additional insets.
Create a UIEdgeInsetsMake() object where you subtract the navigation bar height from the top inset. Then add it to the View Controllers additionalSafeAreaInsets.
Declaration: var additionalSafeAreaInsets: UIEdgeInsets { get set }
This is not an answer, but a workaround:
Keep a reference to the "X" button's top constraint.
In layoutSubviews(), update the constant of the top constraint depending on the "X"'s superview and window safeAreaInsets.
override func layoutSubviews() {
// To support devices with a "safe area". If the receiver has a top safe area, position
// the close button beneath the _window's_ safe area.
// Note that using the receiver's safe area does not work in this case because it includes
// the navigation bar. We want to render the close button beneath the navigation bar.
let windowSafeAreaInsets = UIApplication.shared.keyWindow!.safeAreaInsets
// Only use the safe area if the receiver _and_ window have a top safe area. This handles
// the case of non-safe area devices using a hidden navigation bar.
closeButtonTopConstraint.constant = safeAreaInsets.top > 0 && windowSafeAreaInsets != .zero
? windowSafeAreaInsets.top : 16
// Possibly do something similar for landscape and the "X" button's trailing constraint.
}
I encountered a problem with the scrolling when using the prefersLargeTitles and added UITableView.
If I set the prefersLargeTitles within a navigation controller and its root is a UITableViewController everything is fine, scrolling of the navigation large title works the same way we can see in the system apps (in iOS 11+).
The problem
However, if I use a UIViewController and add a UITableView in it, scroll seems to act differently. Navigation bar is moving more/faster than I actually scroll. It just hides/shows the large title whenever I scroll into a position that just triggers it, so I end up with the totally different feeling.
Turns out that the layout is causing this problem.
The problem occurs if the UITableView use Align top to: Safe Area constraint (besides the bottom, leading and trailing to Safe Area) and is not extended under the bar.
However if I use the extended layout, align top to the superview, I can still use the UITableView and get the correct behaviour of the large title and its navigation bar.
edgesForExtendedLayout = .top
extendedLayoutIncludesOpaqueBars = true
Or use navigation bar's isTranslucent = true which extends it too.
This a little bit wierd i have made UIPageController that works and everything is fine. But when i put it inside UINavigationController, it offset from the for status bar. Than i swipe up on that screen it positions itself right and everything is ok. I don't really understand what is happening. Here are the images
try setting adjustScrollViewInsets to false on UIPageController.
This is the property that determines whether the system should automatically add inset to a UIScrollView in your view controller's view hierarchy when it is being displayed behind transparent bars (here , the navigation bar). What happened here is that the system assumed the bounds of the page controller overlaps with that of the nav bar and so it adds insets so that the view's contents is fully visible and is not obscured by the nav bar. But in this case it is wrong since it seems your page controller's bounds starts at the bottom edge of the nav bar.
I think you can also set the nav bar as opaque to disable the automatic adding of insets.
When I click one of the cells in the table view, it opens a new view with the following code:
let fullResView : FullResponseViewController = self.storyboard?.instantiateViewControllerWithIdentifier("FullResponseView") as! FullResponseViewController
fullResView.receivedPost = post
self.navigationController?.pushViewController(fullResView, animated: false)
When I press back, it increases the distance between the table view and the Top Layout Guide. Representation:
Hierarchy:
I have a tab bar controller, that is embedded in a navigation controller.
The table view is drag & dropped after creating an normal view. So the table view is inside a View.
Table view does contain an header view. When setting a background color for this, it moves together with it, so it should not be anything with those constraints.
constraints for the table view are:
equal with to superview
Align Center X to superview
top space to Top Layout Guide
bottom space to Bottom Layout Guide
I've tried the following:
set this in viewWillAppear:
self.responsesTableView.contentOffset = CGPointMake(0, 0)
self.automaticallyAdjustsScrollViewInsets = false
This did work when I pressed back, then switch to another view in the tab bar, and then switch back again. Without contentOffset it will stay like this forever.
As i seen the OP images that seems like Navigation translucent property Issue. Because after push a viewcontroller there is same 44px white space. so it means if your Navigation translucent property is true then your UITableview start from 0th Y position. And if your Navigation translucent property is false then UITableview start from 44px Y position.
So i guess in between push and back some where UINavigation's translucent become a true and false. make following one line add in your appdelegate class in DidFinish method:
UINavigationBar.appearance().translucent = false
This is appearance of UINavigationBar for make this false globley in your project. Hope that will be fix your issue.
I'm not sure if this is related to your particular issue, but it's worth checking whether your UITableView is the first control on your screen:
Why is there extra padding at the top of my UITableView
Even in the latest version of Xcode, this is a bug. But it's easy enough to fix, if you know how to get around it.