I added UIViewController which has no storyboard to UITabBar.
It seems the view of added VC goes under the tab bar which does not
happen when I add a vc which used Storybaord to UITabBar.
How can I prevent this?
If you don't want the viewcontroller extend to any edges, you can try:
viewController.edgesForExtendedLayout = []
or viewController.extendedLayoutIncludesOpaqueBars = false should also work
I have a simple UICollectionView with a custom cell inside of a navigationController. For some reason when I push a viewController, the collectionView cell changes its layout during the transition.
Is it some common behavior of uicollectionview during viewController transition? Because, for example: labels don't have such problem
When back button was clicked
Green color from collectionView
Adding new view controller
navigationController?.pushViewController(controller, animated: true)
Setting Autolayout using EasyPeasy pod
collectionView.easy.layout([
Top(),
Right(),
Width(view.frame.width),
Bottom(10).to(button),
])
button.easy.layout([
Center(),
Height(60),
Width(300),
])
I think I've found your problem and it's in you AppDelegate. The property isTranslucent which is set to false to your navigation controller seems to cauese this rare problem. A translucent navigation bar will be on top of your viewcontroller's view, like above it. A non-translucent navigation bar pushes down your view controller's view or in other words rezising it so it fits beneath it.. But why the collectionview animates like it does is something I actually cant give a definite answer about. Maybe someone else could do that?..
To keep your navigation bar translucent you can set another property in your viewcontroller which is ´extendedLayoutIncluedsOpaqueBars´ to true.
So.. Do like this. In your AppDelegate:
window = UIWindow(frame: UIScreen.main.bounds)
window!.makeKeyAndVisible()
let controller = TestingNavigationController()
let navigation = UINavigationController(rootViewController: controller)
window!.rootViewController = navigation
let navigationBarAppereance = UINavigationBar.appearance()
navigationBarAppereance.isTranslucent = false
Then, in your view controllers viewDidLoad method add this line
extendedLayoutIncludesOpaqueBars = true
Hope this will solve your problem! :)
Apple Documentation about extendedLayoutIncludesOpaqueBars
I have a UINavigationController displayed as a child view controller taking up part of the screen. I've presented it using a simple embed segue, inside of the storyboard.
That UINavigationController's rootViewController has a small UIView which I'd like to extend past the bounds of the child view controller container.
My hierarchy looks like this:
1) Main View
2) Container Nav Controller
3) Root View Controller
4) UIView which should extend past the bounds of 2
I've set clipsToBounds = false on all containing view, to no avail.
Doing a little bit of view debugging shows a UINavigationTransitionView between 2 and 3, with clipsToBounds = false. I'm pretty sure this is causing the issue (as an enterprise app, I don't mind using private APIs).
How can I allow the view to extend past all containers?
In the ViewController that contains the containerView, under viewDidLoad(), add following code after creating the outlet for the containerView:
let layoutContainerView = self.containerView.subviews.first;
let navigationTransitionView = layoutContainerView?.subviews.first;
navigationTransitionView?.clipsToBounds = false;
This is kinda hacky, basically the first subview of the navigationController's view is a UINavigationTransitionView, in which clipsToBounds = true.
I've set the titleView of a UIViewController's navigationItem after init(). After pushing the VC to UINavigationController, titleView appears correctly at first time. But when I change (re-set) a titleView to an other view, it suddenly disappears.
But when I push another view controller and navigate back, it suddenly appears.
Do I have to perform any actions after re-setting the titleView?
If you are not using tab bar controller, then in viewDidLoad
setting the title as self.title is better.I have mentioned Tab bar Controller because if you have a view controller (in a NavigationController) in a UITabBarController, then if you set self.title it overrides the name of the tab as well as the top title.
I think you maybe code like this:
self.navigationItem.titleView = self.yourView;
If your yourView is a custom class , it maybe remove from superView when you switch your viewcontroller to next one;
So code like this maybe solve your problem:
[self.navigationItem.titleView addSubview:yourView];
I have been reading a lot about iOS7 UI transition.
I am not able to get what these three properties automaticallyAdjustsScrollViewInsets, extendedLayoutIncludesOpaqueBars, edgesForExtendedLayout??
For example I am trying to make my view controllers start below the status bar but I am not able to achieve it.
Starting in iOS7, the view controllers use full-screen layout by default. At the same time, you have more control over how it lays out its views, and that's done with those properties:
edgesForExtendedLayout
Basically, with this property you set which sides of your view can be extended to cover the whole screen. Imagine that you push a UIViewController into a UINavigationController. When the view of that view controller is laid out, it will start where the navigation bar ends, but this property will set which sides of the view (top, left, bottom, right) can be extended to fill the whole screen.
Let see it with an example:
UIViewController *viewController = [[UIViewController alloc] init];
viewController.view.backgroundColor = [UIColor redColor];
UINavigationController *mainNavigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
Here you are not setting the value of edgesForExtendedLayout, therefore the default value is taken (UIRectEdgeAll), so the view extends its layout to fill the whole screen.
This is the result:
As you can see, the red background extends behind the navigation bar and the status bar.
Now, you are going to set that value to UIRectEdgeNone, so you are telling the view controller to not extend the view to cover the screen:
UIViewController *viewController = [[UIViewController alloc] init];
viewController.view.backgroundColor = [UIColor redColor];
viewController.edgesForExtendedLayout = UIRectEdgeNone;
UINavigationController *mainNavigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
And the result:
automaticallyAdjustsScrollViewInsets
This property is used when your view is a UIScrollView or similar, like a UITableView. You want your table to start where the navigation bar ends, because you wont see the whole content if not, but at the same time you want your table to cover the whole screen when scrolling. In that case, setting edgesForExtendedLayout to None won't work because your table will start scrolling where the navigation bar ends and it wont go behind it.
Here is where this property comes in handy, if you let the view controller automatically adjust the insets (setting this property to YES, also the default value) it will add insets to the top of the table, so the table will start where the navigation bar ends, but the scroll will cover the whole screen.
This is when is set to NO:
And YES (by default):
In both cases, the table scrolls behind the navigation bar, but in the second case (YES), it will start from below the navigation bar.
extendedLayoutIncludesOpaqueBars
This value is just an addition to the previous ones. By default, this parameter is set to NO. If the status bar is opaque, the views won't be extended to include the status bar, even if you extend your view to cover it (edgesForExtendedLayout to UIRectEdgeAll).
If you set the value to YES, this will allow the view to go underneath the status bar again.
If something is not clear, write a comment and I'll answer it.
How does iOS know what UIScrollView to use?
iOS grabs the first subview in your ViewController's view, the one at index 0, and if it's a subclass of UIScrollView then applies the explained properties to it.
Of course, this means that UITableViewController works by default (since the UITableView is the first view).
Not sure if you are using storyboards, but if you are, to make your view controllers start below the status bar (and above the bottom bar):
Select the view controller in IB,
In the attributes inspector, deselect 'Extend Edges - Under Top Bars' and 'Extend Edges - Under Bottom Bars'.
I am using storyboards and using the above advice worked however I wasn't exactly sure how to implement it. Below is a short example in swift of how it cleared up the problem by putting the recommended solution into the ViewController.
import Foundation
import UIKit
// This ViewController is connected to a view on a storyboard that
// has a scrolling sub view.
class TheViewController: UIViewController {
// Prepares the view prior to loading. Putting it in viewDidAppear didn't work.
override func viewWillAppear(animated: Bool) {
// this method is an extension of the UIViewController
// so using self works as you might expect.
self.automaticallyAdjustsScrollViewInsets = false
// Default is "true" so this sets it to false tells it to use
// the storyboard as you have it placed
// and not how it thinks it should place it.
}
}
My Problem:
Auto Adjust set to true by default causing a difference between storyboard design and simulator
Resolved:
Code above applied, turning off the auto-adjust.
I solved this problem by adding this line, but my problem was related to a UIView, not UIScrollView
self.navigationController.navigationBar.translucent = NO;
Just bare in mind that
automaticallyAdjustsScrollViewInsets
property works only if some kind of scroll view (table view, collection view,...) is either
The view of VC, or
First subview of this view
Other suggested, that it doest work even if it is the first subview, but there are other scroll views in the view hierarchy.
EDIT (extension DIY)
If you want similar behaviour even if you can't fulfil these conditions (e.g. you have a background image below the scroll view), you can adjust the scroll view insets manually. But please don't set it to constant like 44 or 64 or even 20 like many suggest around SO. You can't know the size ever. There can be the incall/gps/audio notification, navigation bar doesn't have to be always 44 pts etc.
I think the best solution is to use layoutGuide length in didLayoutSubviews:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
scrollView.contentInset = UIEdgeInsets(top: topLayoutGuide.length, left: 0, bottom: 0, right: 0)
scrollView.scrollIndicatorInsets = scrollView.contentInset
}
You can use the bottomLayoutGuide in the same way.