I have a Navigation Controller and a Collection View under it inside my app. And there is a problem: I use large title inside my Navigation bar, so everything inside is not static. When I scroll the collection view cells, the title (I created it manually using UILabel() to move it as I want inside the navigation bar) and buttons move up and the navigation bar takes form of iOS 10 navigation bar, I mean its height. You can see it here:
The normal state of my Navigation Bar with "Prefer large titles" On:
It happens when I scroll my Collection View, everything goes up:
So the question is simple: how to make the force constant height for the navigation bar? I want it to become fixed even while scrolling. Are there any ideas? Is it possible?
And the second question, if the first is impossible: Another solution for my problem is to make the Navigation Bar with "Prefer large titles" Off bigger. I tried this code:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let height: CGFloat = 50 //whatever height you want to add to the existing height
let bounds = self.navigationController!.navigationBar.bounds
self.navigationController?.navigationBar.frame = CGRect(x: 0, y: 0, width: bounds.width, height: bounds.height + height)
}
but it worked only for large titles. So how can I make the navigation bar bigger?
Yes, you can make it fixed. It will not scroll if the very first view in the view hierarchy is not a CollectionView/TableView (ScrollView).
Using Storyboard/Xib:
Consider the following image where a tableView and button are added in scene. Here the navigation bar will collapse on scroll of tableView because tableView is the very first view in viewController's containerView hierarchy attached to the navigation bar.
Now to make the navigation bar fixed, if we just change the order of tableView and button as below, it will disable the collapsing of navigation bar.
To change the order of the view, you have to click, hold and move up/down.
If you have only CollectionView in this scene then you can add a placeholder view at the top and set its height to zero as below,
Programmatically:
If you are setting up view's programmatically then you just need to add a placeholder view at the top or add tableView/collection after adding other views.
e.g,
self.view.addSubview(UIView(frame: .zero))
self.view.addSubview(tableView) // or collectionView
Related
I have a messaging application, the problem is that the first messages are not visible, when I drag the collection view to see the top messages I can see them but when I release the finger, the collection view jumps back, hiding the first 5 messages that are at the top of the screen
As we can see from the image there is a message (actually are 5 messages at the top), however I have to drag the collection view to peek those messages. I thought that the size of the collection view is actually larger that the screen, however both the collectionView.frame.height and the UIScreen.main.bounds.height have the same height, is that ok? .
Here's the code that I use to setup the collection view:
/// Function that configures the ChatViewController collection view
private func configureCollectionView() {
collectionView?.backgroundColor = Theme.current.chatGeneralBackground
collectionView?.alwaysBounceVertical = true
collectionView?.keyboardDismissMode = .onDrag
// Register the chat cell and the loading cellx`
collectionView?.register(ChatCell.self, forCellWithReuseIdentifier: chatCellIdentifier)
collectionView?.register(LoadingCollectionViewCell.self, forCellWithReuseIdentifier: loadingCellIdentifier)
// Initialize the original height of the collection view
collectionViewOriginalHeight = collectionView.frame.height
}
What am I doing wrong?
As of iOS 7.0, all views automatically go behind navigation bars, toolbars and tab bars to provide what Apple calls "context".
For example, if you don't want a view controller to go behind any bars, use this in viewWillAppear
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
self.edgesForExtendedLayout = []
}
It seems to be the problem with constraints, if you are using custom navigation bar top constraints should be in reference to it. If using default navigation controller, you might need to give the top constraint to 44 from safe area.
However UIScreen.main.bounds.height consists of complete screen including the top navigation bar and 20 px of status bar. For collectionView.frame.height you need to minus these values.
I'm trying to understand how to change the height of a navigation bar. Whenever I insert one into my app, it is shorter than all the navigation bars used in Apple's stock apps (Messages and Settings for example). I would like it to get to that height because when I try to add a bar button, it conflicts with the status bar. I also read that as a developer you shouldn't change the height of the navigation bar so I'm a bit confused. Finally, I looked at this Stack Overflow page: How can I change height of Navigation Bar Swift 3.
I tried to implement the code...
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let height: CGFloat = 50 //whatever height you want
let bounds = self.navigationController!.navigationBar.bounds
self.navigationController?.navigationBar.frame = CGRect(x: 0, y: 0, width: bounds.width, height: bounds.height + height)
}
...but my app crashed when I did so.
I'm using Xcode 8.2 beta with Swift 3.
I dont think you can change size of navigationBar.
But this is how would i recommend you to do it.
Remove default navigation bar.
Create a view which is similar to a navigation bar like you design add constrains> leading,trailing,top and height for that
view. so basicly pin it to top, left and right with your design's
height.
Add 2 buttons left and right if needed which would look similar to navigation bar. add button constrains> leading, top, bottom and
width for left one and trailing,top, bottom and width right one.
Add a UILabel which would be your navigation bar title., add label constrains leading with left button, trailing with right button, top
and bottom with navigation view you created. Make uilabel text
centered.
Here you go u have your custom navigation bar.
On each controller all u have to do is CMD+C and CMD+V on the other controller add leading,trailing and top constrains.
Hope it helped.
It is possible, and simple, to add an independent navigation bar and have it match the normal navigation bar height and rotation functionality. Here is how to do it (link includes a video):
In Interface Builder:
Add a UINavigationBar to your view, positioned at the Top Layout Guide location.
Set constraints for Leading Space to Container Margin, Trailing Space to Container Margin, and Top Space to Container — all with ‘Relative to margin’ deselected and a Constant value of 0 (zero).
With the Navigation Bar selected, in the Identity Inspector, add a key path called barPosition. Give it a Number type, and a value of 3.
That should be all you need. However, if you’ve completed these steps and your project doesn’t seem to like the key path, then continue as follows:
Remove the barPosition key path from the Navigation Bar’s Identity Inspector.
Add an IBOutlet for the Navigation Bar to your view controller.
Set your view controller to be a UINavigationBarDelegate.
Add the delegate method func position(for bar: UIBarPositioning) -> UIBarPosition to your view controller, and return a value of UIBarPosition.topAttached.
I want to have the Tab Bar at the top of the screen. One post suggested to do the followings (I put the following code in the viewDidLoad() of the UITabBarController) :
CODE
let tabBar = self.tabBar
// yStatusBar indicates the height of the status bar
let yStatusBar = UIApplication.sharedApplication().statusBarFrame.size.height
// Set the size and the position in the screen of the tab bar
tabBar.frame = CGRectMake(0, yStatusBar, tabBar.frame.size.width, tabBar.frame.size.height)
There are 2 problems with this solution:
The bottom of the screen is left with a black region where the tab bar was
The Tab bar covers the view at the top of the screen - the constraints of that view is relative to the device but they should be relative to the Tab bar. However when the screen is designed in the IB there is no Tab bar to relate to.
Is there a way to overcome these problems? P.S. I am new to IOS
let tabBar = self.tabBarController?.tabBar
// Set the size and the position in the screen of the tab bar
tabBar?.frame = CGRect(x: 0, y: self.view.frame.height, width: (tabBar?.frame.size.width)!, height: (tabBar?.frame.size.height)!)
Although it is against the human interface guidelines there exist a hack if you really want to.
You could create a blank UIView in your storyboard (with proper constraints set up) that would essentially be the placeholder for the tabBar when loaded.
You then set top constraints for your other views relative to this view that you have setup.
This works, but probably not best practice to do so
In my view controller I have a UIView (drawer view) that sits below the visible screen with just the top poking out (a tab). This tab can be tapped and the UIView will animate up and fill most of the screen. The view is set like so:
drawerView = DrawerView(frame: CGRect(x: 0, y: UIScreen.mainScreen().bounds.size.height - DrawerView.submitTabHeight, width: UIScreen.mainScreen().bounds.size.width, height: UIScreen.mainScreen().bounds.height*0.75))
drawerView.delegate = self
view.addSubview(drawerView)
Below is a screenshot of the setup:
I have to present this view controller from a tab bar controller. I want to hide the tab when the view controller is loaded and I did this by setting Hide Bottom Bar on Push in the IB. The problem I have now is that when I push the view controller the drawer view is temporarily out of place. It is higher up than it should be by the height of the tab bar (shown by the dotted line on the screen). It then jumps back to the actual position it should be in. Any ideas what I might be doing wrong here? Any pointers on this would be greatly appreciated! Thanks
Just hide the tabbar before pushing the viewcontroller.
if (self.tabBarController) {
self.tabBarController!.tabBar.hidden = true;
}
I created a UINavigationController and a UIViewController. With this setup the view looks like this:
This is what I want. The content "Test Text" does not appear behind the status bar.
Now I created my own UINavigationBar in the UIViewControllers:
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.setNavigationBarHidden(true, animated: false)
let newNavBar:UINavigationBar = UINavigationBar(frame: CGRectMake(0, 0, CGRectGetWidth(self.view.bounds), 64))
newNavBar.tintColor = UIColor.whiteColor()
newNavBar.translucent = true
self.view.addSubview(newNavBar)
}
The result is the following:
The content is behind the new navigation bar.
How can I prevent the content from being behind the new navigation bar?
When you add Navigation Bar in view controller then NavigationBar will take 64pixel ( 20 pixel status bar and 44 pixel navigation bar ) so you need to start your layout after 64pixel from top.
If your content is a UIScrollView, use the contentInsets property to adjust where your content starts, this makes the scrollview be able to scroll the specified amount of pixels "too far", and thus show your content immediately below your custom UINavigationBar.
If your content is not a UIScrollview, then just offset the content with a constraint (you could link it to an IBOutlet, so you can change it if you dynamically change from the old to the new UINavigationBar).