Moving Tab Bar to the top of the screen swift - ios

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

Related

Static/fixed Navigation Bar in iOS

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

Change Navigation Bar Height

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.

Hide tab bar causing incorrect UIView positions

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;
}

Autolayout with Navigation Bar - Remove Specific Constraint

I'm building an application for iOS, which is using a navigation controller. I want to put a view in the titleView, and have it fill the whole width of the navigation bar.
I'm calling setupNavBar in viewDidLoad of the view controller that is embedded in the navigation controller. Here is how I do:
func setupNavBar() {
let navBar = navigationController?.navigationBar
// navBar!.translatesAutoresizingMaskIntoConstraints = false
// navBar!.frame.size.height = CGFloat(100)
let searchBar = UIView(frame: navBar!.frame)
searchBar.bounds = CGRectMake(0, 0, navBar!.frame.width, navBar!.frame.height)
searchBar.backgroundColor = UIColor.brownColor()
navigationItem.titleView = searchBar
}
But the view (brown - "searchBar"), doesn't cover the full navigation bar:
So I figured out that the problem was related to Autoresizing and Constraints, because if I call navBar!.translatesAutoresizingMaskIntoConstraints = false, I can freely set the sizes of views frame, so there must be some constraints that change the view's bounds. But I would like to keep as much of the autolayout behaviour as possible.
Is there a way to only change the contraints on the titleView?
I'm doing everything programmatically, I don't use the storyboard or xib's!
EDIT:
But it doesn't seem like there is any constraints on either navigationItem or navBar:
for someObject in navigationItem.titleView!.constraints {
print(someObject)
}
It doesn't print any constraints. neither if I use navBar.constraints!
EDIT 2:
I have a screenshot from "View UI Hierarchy" from the debug navigator:
It seems that the view(brown) alligns with the Navigation Bar Back Indicator View, maybe this is a clue to what causes the problem?
How come the view is resized?
Two different suggestions here:
1. You can try the
navigationItem.titleView.sizeToFit()
Otherwise you could set the background colour of the navbar to brown as it appears you wish the brown bar to cover the entire width of the navbar. If you want to add other views on top of that you then can.
You could also try to make an outlet to the title view and add an NSLayoutConstraint using
navigationItem.titleView.addConstraint(NSLayoutConstraint: NSLayoutConstraint)
I am not entirely sure whether that will work, however.

Black bar flashes at top of UITableView when pushing to view with "Hides Bottom Bar When Pushed" in IB

This is a weird error that may just be an issue in Xcode for all I know. I have a tab bar controller where the first view is a UITableView with (obviously) a number of cells. When you select a cell, I've set up a segue on the MainStoryboard to go to a detail view controller. I want the tab bar to be hidden when I go to the detail view, so I went into the storyboard, chose my detail view, and clicked "Hides Bottom Bar on Push" in the editor screen that starts with "Simulated Metrics."
Everything works just fine, except that when I tap on a cell, a black bar flashes at the top of the UITableView screen, dropping the tableview cells down (as if the cells are falling down below the tab bar at the bottom), just before the screen pushes over to the detail view. The effect isn't harmful at all, but it's very disconcerting, and I'd like to smooth that out.
The only fix I've found is to uncheck the "Hides Bottom Bar when Pushed" option on the storyboard. That indeed does get rid of that black bar flash, but of course the tab bar stays on the screen when I go to the detail view, which is what I don't want.
Any ideas?
Just for completeness' sake, I went ahead and ran
[self.navigationController setToolbarHidden:YES animated: YES];
on the detail view controller's viewWillAppear method (and even tried it with the storyboard option both on and off), but there was no difference. The toolbar did indeed hide just fine, but I still got that black line at the top. So weird.
I know it is too late !!! I ran into same issue. It seems like the Auto resizing mask for the view was incorrect to be exact the UIViewAutoresizingFlexibleTopMargin. I checked this on in the xib file. If you are trying to do it in code make sure this flag -UIViewAutoresizingFlexibleTopMargin - is not included in the autoresizing mask.
Hope this will help some one in the future
I know it is a bit late, but I have same problem and I can't solve it with any of the previous answers. (I suppose this is the reason non was accepted).
The problem is that view size of the SecondViewController is same as view size of a previous ViewController, so too small to fit in a ViewController with Toolbar hidden. Thats why black background of a UITabBarController is visible at the top when transition is happening, and on a viewDidAppear view will stretch on right size.
For me it help to subclass root UITabBarController and set background color to same background color as SecondViewController has.
class RootViewController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = Style.backgroundColor
}
}
Then you can leave checkbox checked inside storyboard and it will look ok.
P.S.
If you have some views, that is position on the bottom part of the view, you need to set bottom constraints so they are smaller by 49 (because this is the height of the toolbar), and then on viewDidAppear set the right constraint.
For example:
I have view that need to be position 44 px from bottom edge. Before, I have constraint set to 44 and I have some strange behaviour of that view. It was placed to height and then jump on the right place.
I fix this with setting constraint to -5 (44-49), and then in viewDidAppear set the constraint back to 44. Now I have normal behaviour of that view.
Wow I just had the same issue now, very painful, and no info on the net about it.
Anyway, a simple workaround for me was to change the current view's Frame moving the y coordinates up and making the height bigger by the height of the tab bar. This fixed the problem if done straight after pushing the new view onto the navigation controller. Also, there was no need to fix the Frame afterwards (it must be updated when the view is shown again).
MonoTouch code:
UIViewController viewControllerToPush = new MyViewController();
viewControllerToPush.HidesBottomBarWhenPushed = true; // I had this in the MyViewController's constructor, doesn't make any difference
this.NavigationController.PushViewController(viewControllerToPush, true);
float offset = this.TabBarController.TabBar.Frame.Height;
this.View.Frame = new System.Drawing.RectangleF(0, -offset, this.View.Frame.Width, this.View.Frame.Height + offset);
Objective C code (untested, just a translation of the monotouch code):
UIViewController *viewControllerToPush = [MyViewController new];
viewControllerToPush.hidesBottomBarWhenPushed = YES; viewControllerToPush.hidesBottomBarWhenPushed = YES;
float offset = self.tabBarController.tabBar.frame.size.height; float offset = self.tabBarController.tabBar.frame.size.height;
self.view.frame = CGRectMake(0, -offset, self.view.frame.width, self.view.frame.height + offset); self.view.frame = CGRectMake(0, -offset, self.view.frame.size.width, self.view.frame.size.height + offset);
Do this in viewWillAppear of detailViewController, it should work fine
subclass your navigation controller, or just find the navigation bar
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
let backdropEffectView = navigationBar.subviews[0].subviews[0].subviews[0] //_UIBackdropEffectView
let visualEffectView: UIVisualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .Light))
visualEffectView.frame = backdropEffectView.frame
backdropEffectView.superview?.insertSubview(visualEffectView, aboveSubview: backdropEffectView)
backdropEffectView.removeFromSuperview()
}

Resources