I have a simple case where I am pushing a new viewcontroller onto a navigation controller stack. This VC uses a xib and has a UISearchBar that is constrained to the top and left 'container' which in this case is simply the main View.
When I push this VC on the stack the search bar is not seen. This is because the nav bar rests on top taking up the first 50 or so y points of the device screen. (starting after the status bar presumably).
If I set the top container auto-layout constraint to 50, or some y-offset sufficient to counteract the height of the nav bar, I will see the search bar.
I am working on a project where I am pushing VC's onto a nav stack of a UINavigationController I did not create. I am wondering what reasons could lead to this (what i would call buggy) behavior. My understanding was that any viewController in a navController would have it's main view's frame adjust in the presence of nav/status/tab bars. What can I do to ensure that origin (0,0) starts at screen origin + status bar height + nav bar height? Furthermore, I would also like my VC's mainView's lower bound to end at the top of the tab bar also present on screen. I have looked into various UIView and ViewController properties and have not found a satisfying solution.
If you use xib file for designing your view controller, you should add this code to your viewDidLoad method:
self.edgesForExtendedLayout = UIRectEdgeNone
This line will make your view controller's view is laid out under the navigation bar.
Conventionally, any new UIViewControllers are done on storyboards and some developers hook up segues between the first and second UIViewController. The reason for this is because by implementing a pushing segue, the secondUIViewController over the first one, the second one will inherit whatever properties the first one had (such as navigation bars, toolbar, tabbar) and it shows on the storyboard immediately.
So then it will be easier to work on the second UIViewController knowing how much space to allocate to UINavigation or UITabbar.
If your VC is done on an XIB interface instead of being hooked to the UINavigationController controlled stack of previous ViewControllers, then I am guessing you are not seeing the space that UINavigationBar and UITabBar supposedly takes up on your interface?
Perhaps you could try setting the constraints to begin at 64 points below the Top Layout Guide (to make space for UINavigationBar) and 49 above the Bottom Layout Guide (to make space UITabbar).
Related
I have a UIViewController that contains a UICollectionView pinned to all edges of the view. This view controller is inside a UINavigationController.
I want to gradually hide the navigation bar as I scroll down in the collection view. At the point that I have scrolled the distance of the height of the nav bar, the nav bar should be completely hidden. If I scroll back up it should gradually show the nav bar.
I have tried all the open source navigation bars on github, but none of them work correctly with iOS 12.
How can I achieve this?
UICollectionView is a subclass of UIScrollView and therefore you have access to its scrollViewDidScroll delegate method. Your UIViewController is also owned by its navigation controller, so you can create an instance property in the view controller, like navigationDelegate: UINavigationController?, that will act as a delegate. In the navigation controller, set that property equal to self and manipulate the nav bar however you want through the scroll delegate. Absolutely no need for third-party scripting for something this standard and basic.
So, adding a view that appears over the UINavigationBar in a UINavigationController is easy enough:
self.navigationController?.view.addSubview(testView);
However, getting that UIView to push/transition alongside UIViewController changes in that navigation flow is more tricky. Aside from simply fading the view alpha from 1 to 0 or vice versa on appear/disappear, is there an elegant solution/hack for getting the horizontal position of the view to stay centered, for example?
EDIT: The reason why setting titleView on the UIViewController's navigationItem won't work is because when another view is popping it clips the titleView... (compare this image to the one above)
I have an app that uses a Nav Contoller as it's initial VC, which then has a root UIViewContoller that contains a UIView at the top half, and a UIContainerView at the bottom. In the UIContanerView, I'm embedding a working UICollectionView that contains image buttons that segue to detail views.
The problem is that white space now shows up at the top of the UICollectionView. Given this is around 64 pixels high, it appears to be a ghosting of a Nav Bar 44px + Status Bar 20px = 64.
And if I scroll up everything looks fine and works as expected, and it also allows me to show you what I expected the layout to look like upon launch:
A snippet of my storyboard is below if that helps:
yes, that could be because child view controller embedded in container view gets the impression, that it is a direct child of UINavigationController, which in turn make collectionView leave top 64 pt insets.
TO solve this problem,In your child view controller interface builder, unmark adjust scrollView insets
This should solve your problem
UPDATE
As Dan suggested, we can also fix it programatically, by calling
automaticallyAdjustsScrollViewInsets = false
in viewDidLoad() of your UIViewController
I have a design for an app with 3 screens where the
A) initial screen shall not show top navigation bar
B) second screen shall show top navigation bar (with a nav back button to A)
C) third screen shall not show top navigation bar (but a normal button back to B)
I chose to embed the view controllers in a navigation bar.
But doing so the AutoLayout constraints on the first view controller poops out plenty of warnings - because the embedded UIViews are pinned to the top bar - which is really annoying.
Of course if I "hide" the navigation bar in the storyboard designer, I am no longer able to add the required buttons for by B screen.
An alternate option COULD be to implement the navigational properties of my app all manually, but I really want to avoid doing this.
What is the preferred (best practice) solution to this?
Its Too simple...
you just set hidden attribute of navigation controller in viewWillAppear ex:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.navigationController.navigationBarHidden=YES/NO; //as per your requirement
}
As noted in #SonuPatel answer, you can set the navigation bar to hidden relatively easily. For layout:
In controllers A and C, make your top layout offsets relative to the view and not the top layout guide. This will make them layout under the navigation bar when it is not visible. Hidden items usually still contribute to layout, so the topLayout guide is unaffected by it being hidden.
In controller B, make your top layout relative to the top layout guide to keep it below the navigation bar.
For a UITableViewController, you can get this for free by selecting Extend Edges Under Top Bars in the attribute inspector.
I have a UINavigationController with standard UINavigationBar. When presenting certain UIViewControllers and orientations, the UINavigationBar may or may not appear and it may or may not have a prompt element. This means that the bar height changes frequently.
I have some subviews below the UINavigationBar set with NSLayoutConstraints to topLayoutGuide. It generally lays out as expected, adjusting vertical position of the subviews appropriately based on the height of the UINavigationBar. What it does not do is move the subviews at times when the UINavigationBar is animated after the view is already displayed.
Specifically, coming from a state with UINavigationBar hidden, transition to a UIViewController which does not hide the navigation bar to one which does. The view displays, then navigation bar animates into place. The subviews do not move down. If I rotate the device, every things lays out appropriately again. Only when animating the navigation bar in and out or to display/hide the prompt I not find a hook to reevaluate the constraints.
I tried [self.view updateConstraints] and [self.view updateConstraintsIfNeeded] in various places such as viewDidAppear, viewDidLayoutSubviews. Nothing seems to update that topLayoutConstraint.
I am familiar with edge restraints, translucent navigation bar and other various methods of keeping the entire view from appearing under the navigation bar. I do want to keep view full size and I want the translucent bar so these are not solutions for me. It seems the constraints should handle this automatically, hence the "auto" in auto layout.
To simplify, for recreation, UINavigationController with rootViewcontroller showing normal navigation bar with just a title. In viewDidLoad of the next presented viewController I have [self.navigationContoller setPrompt:self.myPrompt]. The view is presented, when the prompt is set, the navigation bar grows larger. Some labels below the bar are set with relation to topLayoutGuide, which places them correctly initially. I expect they would move down when the bar grows. Rotate device back and forth, they now layout correctly. Pop the viewController and push back to top, repeats as above.
So, it turns out it was all me. After trying all manner of forcing layout updates in all sorts of ways, the solution was to move the [myView setPrompt:myPrompt] out of viewDidLoad and call it in viewDidAppear instead.
Works completely as expected. Navbar grows, subviews shift and shrink as needed. Now I have to hunt down all the experimental code I plastered everywhere trying to do it wrong.