I will appreciate if someone can show how to use the topLayoutGuide and bottomLayoutGuide properties of UITableViewController introduced in iOS 7. Thank you.
The topLayoutGuide and bottomLayoutGuide properties are inherited from UIViewController and implements the UILayoutSupport protocol. They are designed to be used with AutoLayout, but can also be used directly without the use of AutoLayout.
In the case of topLayoutGuide, the property indicates the highest vertical extent for content that you don't want to appear behind a translucent or transparent UIKit bar (such as a status or navigation bar). So, if your view controller has been pushed onto a UINavigationController stack, topLayoutGuide will tell you how many points from the top of the screen the status bar and navigation bar cover. You can use this value scroll content in a UIScrollView to just below the navigation bar or ensure other content in your view isn't being covered by the UINavigationBar.
Keep in mind that the value of topLayoutGuide depends on the view controller and whether or not it's contained within another view controller. From Apple's UIViewController documentation:
The object that constrains the value for this property depends on
whether or not the view controller is a child of a container view
controller (such as a navigation or tab bar controller), as follows:
• A view controller not within a container view controller constrains
this property to indicate the bottom of the status bar, if visible, or
else to indicate the top edge of the view controller's view.
• A view controller within a container view controller does not set this
property's value. Instead, the container view controller constrains
the value to indicate:
The bottom of the navigation bar, if a
navigation bar is visible
The bottom of the status bar, if only a
status bar is visible
The top edge of the view controller’s view, if
neither a status bar nor navigation bar is visible
Here's a piece of code I use to move a UITextField in response to the showing of the keyboard. I move the textfield to just below the navigation bar.
CGFloat length = self.topLayoutGuide.length;
_feedback.frame = CGRectMake(_feedback.frame.origin.x, length + 5.0, _feedback.frame.size.width, _feedback.frame.size.height);
Using bottomLayoutGuide is exactly like using topLayoutGuide, except the bottomLayoutGuide refers to the lowest vertical extent for content.
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.
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).
I have created an application which needs to have a bar above the navigation bar and other views. To accomplish this, I am using a view controller with a view for the top bar, and then a container view for everything else. Sometimes, the top bar needs to be hidden. I'm using autolayout to hide the top bar (set its height to 0), and the container view expands to fill the screen (container top equal to the top bar bottom). The container view contains a navigation controller because I need a navigation bar below the top bar sometimes. When I start the app, this all works fine as shown below:
As you can see, the navigation bar stays the desired height, which is expanded to include the status bar
However, when the top bar is tapped, I use a segue to present (not push) a view controller from my root view controller (not the container), and then I look at the same screen with the navigation bar, the navigation bar is no longer extended and it overlaps the status bar as seen below:
Why would presenting a view controller break this? And then how could I rectify this or prevent it?
One possible solution I could do is present a view controller from within the container view, that works, I would just have to set the current view controller in the container to a delegate of the root controller, so that when the top bar is tapped, it tells the view controller in the container to present the new view controller. This would not be my first option however, especially if there are other scenarios which cause this problem.
Thanks for any help!
You need to turn automaticallyAdjustsScrollViewInsets off for all of your child view controllers and manage the insets (or setup so they aren't required) yourself. By default automaticallyAdjustsScrollViewInsets is on for all view controllers (which is what you want for 'full screen' presented VCs.
At the moment you see controllers almost randomly updating to reorganise themselves for the scroll insets as the VC hierarchy changes.
I'd probably turn automaticallyAdjustsScrollViewInsets off for all VCs (apart from root) and change your header view so that it's full height or status bar height (which should be the length of the topLayoutGuide of the root VC). When collapsed to status bar height your header view could also change colour to match that of the current top VC.
I'm trying to add a custom view above the navigation bar as displayed on the following image .
What I've tried so far is to add the view as a subview of the navigation bar - Did not work
Add the custom view first on Interface builder and then add a navigation bar manually - This seems to mess up with my navigation as the default navigation controller has it's own navigation bar.
Is this a bad approach on its own ?
If this is a view that will appear above all navigation bars in the app, why not use a Container View?
Make the Container View fill the screen, but give it a 20 point top margin to fit your custom green view. Then when you add your main view controller (wrapped in a navigation view controller) to the Container View, it will show your green view above it.
If you don't want your margin in a particular screen, do the following:
Add a constraint to the top margin and add an outlet to it so you can modify the constraint's constant in code.
Then, in any screens where you don't need the margin, access the parent view controller view and set the constraint's constant to zero.
let myParentViewController = self.parentViewController as? MyParentViewController
myParentViewController.myTopMarginLayoutConstraint.constant = 0
Don't forget to reset it to 20 (or whatever) when you go to a screen where you need the top margin again.
I am using a search bar plus controller for a UITableview in my MasterController. When the view shows up, the navigationbar in the MasterController is black until the view fully loads (not sure why?). In order to fix this I set the self.navigationController.navigationBar.translucent = false; This fixed the issue I was having with the navigation bar being black initially, but now it looks like when I click a cell in the uitableview of the MasterController, the content in the DetailView that loads shifts down approximately the size of the search bar, but it's just blank space above the content that has been shifted... When I remove the translucent property in the MasterController the content in the DetailView is fine and not shifted...
SO my question is, what is shifting this content down and how can I stop the content from being shifted AND having an opaque navigation bar...
In iOS 7, by default your view controller's view extends under a translucent navigation bar when contained in a UINavigationController but not on an opaque one. You could set the extendedLayoutIncludesOpaqueBars property of the view controller if you want it to extend under opaque nav bars too.
When you say your scroll view is shifted on your detail view controller it's probably because its y origin is not set to zero to offset for your view extending under a translucent nav bar, but because your nav bar is now opaque and your view is not extending under it the space is now visible.
One thing more view controllers will actually automatically add insets on scroll views they contain so that their contents are not obscured when the view controllers view extends under navigation bars. It is set by the automaticallyAdjustsScrollViewInsets property which is by default is set to YES.