iOS TabbarViewController hide the tab bar - ios

I have a viewcontroller that it implement UITabbarViewController, and I want to hide
the tab bar and override it by myself,
self.tabBar.hidden = YES;
the tab bar disappeared BUT there is a blank area(the blue one) at the bottom of the view.
I dont want the blank area , how can I fix this? Thank you.
edit: the blue area is:
self.view.backgroundColor = [UIColor blueColor];

We've done exactly the same in our application. To hide the default TabBar, simply override the hidesBottomBarWhenPushed method in your parent view controller (or in every view controller in your App)
#pragma mark - Overriden UIViewController methods
- (BOOL)hidesBottomBarWhenPushed {
return YES;
}
EDIT: This value can also be set from Storyboard:

My UITabBarController is housed within a container view. Checking "Hide Bottom Bar on Push" was not working for me. Instead I created a subclass of the tab bar controller and hid the tab bar programmatically.
class FooTabBar: UITabBarController {
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.tabBar.isHidden = true
}
}

I don't think there's an easy way to fix this because UITabbarViewController is probably your super view and all "inner" views' height = screenHeight - tabBarHeight - navBarHeight.
Maybe you can try to resize your inner view controller manually but then I think you might have problems with Apple's AppStore submission process, because I think this violates general iOS user experience.

And this is how you'd do the override (UIViewController) in Swift:
override var hidesBottomBarWhenPushed: Bool {
get { return true }
set { super.hidesBottomBarWhenPushed = newValue }
}

Related

How to make Navigation Bar translucent on specific view?

I have a drill down hierarchy of three views, all embedded in a Navigation Controller. I want the last view to have the navigation bar translucent, but on return to the previous two first views the Navigation Bar not translucent. I have tried implementing the self.navigationController?.navigationBar.translucent = true; code in the views viewDidLoad func but no avail, it just remains the same. What should i implement?
Sorry if I am miss understanding this but you want to make the translucent bar disappear again and become hidden? If thats the case then you should set the bar back to hidden in the ViewWillDisappear()
That should solve your problem!
In the last view
override func viewWillAppear(animated: Bool) {
self.navigationController?.navigationBar.translucent = true
}
override func viewWillDisappear(animated: Bool) {
self.navigationController?.navigationBar.translucent = false
}
You may try this method in your program.
Remember to execute this method in - (void)viewWillAppear:(BOOL)animated method.
If you're NOT using a navigation controller in your program, you're gonna replace self.navigationController with your own navigationBar.
- (void)navigationBarInitializationWithTransparentOption:(BOOL)isAffirmative
{
//An optional statement below, just to make sure the navigationBar is in its place:
self.navigationController.navigationBarHidden = NO;//(or separate ".navigationBarHidden" to ".navigationBar.hidden")
//
//TO MAKE THE BACKGROUND OF THE CURRENT NAVIGATION BAR TRANSLUCENT:
[self.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
[self.navigationController.navigationBar setTranslucent:isAffirmative];
//set NO in the following statement will leave the border of the navigation bar visible
self.navigationController.navigationBar.clipsToBounds = YES;
}

How to prevent status bar from overlapping content with hidesBarsOnSwipe set on UINavigationController?

I'm trying to use the new feature added in iOS 8 - hiding the navigation bar while user is scrolling the table view (similar to what mobile Safari does). I'm setting the property hidesBarsOnSwipe of UINavigationController to YES in viewDidAppear method of UITableViewController:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if([self.navigationController respondsToSelector:#selector(hidesBarsOnSwipe)]) {
self.navigationController.hidesBarsOnSwipe = YES;
}
}
The navigation bar hides when the view is being scrolled. So far so good. But the status bar is still visible and my table view contents show through it, which looks ugly:
I tried setting edgesForExtendedLayout to UIEdgeRectNone or adjusting the contentInset of the table view, but it didn't help. Is there any other solution to hide the status bar along with the navigation bar, or make it opaque?
Actually it is pretty easy to do. You just need to connect navigation isNavigationBarHidden property with status bar.
Objective-C
- (BOOL)prefersStatusBarHidden {
return self.navigationController.isNavigationBarHidden;
}
Swift <= 2.3
override func prefersStatusBarHidden() -> Bool {
return navigationController?.navigationBarHidden ?? false
}
Swift 3.0
override var prefersStatusBarHidden: Bool {
return navigationController?.isNavigationBarHidden ?? false
}
And be sure you have "View controller-based status bar appearance" = "YES" in your application .plist file.
Building off of anas' answer, I have a working solution (I'm assuming tableViewController is your UITableViewController instance):
In a UINavigationController subclass (or also potentially from tableViewController):
- (void)viewDidLoad {
if ([self respondsToSelector:#selector(barHideOnSwipeGestureRecognizer)]) {
// iOS 8+
self.hidesBarsOnSwipe = YES;
[self.barHideOnSwipeGestureRecognizer addTarget:self action:#selector(swipe:)];
}
}
- (void)swipe:(UISwipeGestureRecognizer *)recognizer {
BOOL shouldHideStatusBar = self.navigationController.navigationBar.frame.origin.y < 0;
tableViewController.hideStatusBar = shouldHideStatusBar;
[UIView animateWithDuration:0.2 animations:^{
[tableViewController setNeedsStatusBarAppearanceUpdate];
}];
}
In your tableViewController:
#property(nonatomic, getter = shouldHideStatusBar) BOOL hideStatusBar;
- (BOOL)prefersStatusBarHidden {
return [self shouldHideStatusBar];
}
Let me know if this doesn't work for you. A few non-obvious things:
self.navigationController.navigationBar.frame.origin.y was -44 (the negative height of the navigation bar) when hidden, and 20 (the height of the status bar) when visible. There was no in-between, even during animations, so a negative value == hidden and a nonnegative value == visible.
The child view controller is the one queried for whether or not the status bar should be hidden. In my case, I have a UIViewController within a UINavigationController within a UITabBarController, and it didn't work until I overrode prefersStatusBarHidden on the UIViewController.
Since a hidden status bar has no frame, your content might jerk upwards 20 points unless you wrap the call to setNeedsStatusBarAppearanceUpdate in an animation block.
Hopefully the syntax is correct; I backported this from my Swift code.
That new property comes with its barHideOnSwipeGestureRecognizer.
From the UINavigationController Class Reference:
You can make changes to the gesture recognizer as needed but must not
change its delegate and you must not remove the default target object
and action that come configured with it. Do not try to replace this
gesture recognizer by overriding the property.
But you can add a target:
[self.navigationController setHidesBarsOnSwipe:YES];
[self.navigationController.barHideOnSwipeGestureRecognizer addTarget:self action:#selector(swipeGesture:)];
... and do whatever you want in the callback:
- (void)swipeGesture:(UIPanGestureRecognizer*)gesture
{
// Tweak the status bar
}
You might have to manually switch on the gesture states, figure out when to hide/show the status bar, etc. Hope that helps!
The answer from #iOSergey works perfect!
Here is the solution in Swift 1.2. Add the following code to the views .swift file:
override func prefersStatusBarHidden() -> Bool {
return self.navigationController!.navigationBarHidden as Bool
}
If you want to hide status bar with animation:
override func preferredStatusBarUpdateAnimation() -> UIStatusBarAnimation {
return .Slide
}
override func prefersStatusBarHidden() -> Bool {
return navigationController?.navigationBarHidden ?? false
}
After much struggle, I was finally able to solve this.
Change TableViewController to UIViewController
Drag a TableView to the UIViewController and align it right underneath the navigation bar in the main.storyboard
Add missing constraints.
click on tableview and inspect the constraints
set bottom space to: superview to 0
set trailing space to superview to 0
set leading space to superview to 0
set "Align Top to: Top Layout Guide.Top to 0 (Very Important)
Add the following code to the UIViewController's viewDidLoad function:
// Create a solid color background for the status bar (in Swift Code)
let statusFrame = CGRectMake(0.0, 0, self.view.bounds.size.width,
UIApplication.sharedApplication().statusBarFrame.size.height)
var statusBar = UIView(frame: statusFrame)
statusBar.backgroundColor = UIColor.whiteColor()
self.view.addSubview(statusBar)
What you are doing is creating a solid bar right beneath the navigation bar. As the navigation bar moves up, the solid bar move up too and right behind the status bar.
The only problem is that when you rotate the screen side ways, the white bar still there even though the status bar disappears.
Okay I spent all day doing this, hopefully this helps some people out. There's a barHideOnSwipeGestureRecognizer. So you could make a listener for the corresponding UIPanGesture, noting that if the navigation bar is hidden then its y origin is -44.0; otherwise, it's 0 (not 20 because we hid the status bar!).
In your view controller (swift 2):
// Declare at beginning
var curFramePosition: Double!
var showStatusBar: Bool = true
self.navigationController?.barHideOnSwipeGestureRecognizer.addTarget(self, action: "didSwipe:")
...
override func viewDidLoad(){
self.navigationController?.hidesBarsOnSwipe = true
curFramePosition = 0.0 // Not hidden
self.navigationController?.barHideOnSwipeGestureRecognizer.addTarget(self, action: "didSwipe:")
...
}
func didSwipe(swipe: UIPanGestureRecognizer){
// Visible to hidden
if curFramePosition == 0 && self.navigationController?.navigationBar.frame.origin.y == -44 {
curFramePosition = -44
showStatusBar = false
prefersStatusBarHidden()
setNeedsStatusBarAppearanceUpdate()
}
// Hidden to visible
else if curFramePosition == -44 && self.navigationController?.navigationBar.frame.origin.y == 0 {
curFramePosition = 0
showStatusBar = true
prefersStatusBarHidden()
setNeedsStatusBarAppearanceUpdate()
}
}
override func prefersStatusBarHidden() -> Bool {
if showStatusBar{
return false
}
return true
}
Another way to do it is just add another view (above the tableview or collectionview or webview or scrollview or whatever) and set the view's top constraint to "Superview.Top" and its bottom constraint to "Top Layout Guide.Bottom" ,set the view's background color
and thats it , you can even do it all in Interface Builder without any code.
And if you want to respond to that event you can add a keypath observer to the view's bounds change , or subclass the view and override its bounds setter...
You need to connect navigation isNavigationBarHidden property with status bar.
return self.navigationController.isNavigationBarHidden;

iOS - UINavigationController, Hide navigationBar

I have a minor trouble hiding the navigationBar for my UINavigationController
I have added:
self.navigation!.navigationBar.hidden = true
This, unfortunately leaves some kind of background (white) left behind the white status bar that pushes the content (green) downwards, and an unwanted scroll behaviour where I can drag the content up and down to show/hide the white background. What I need is for the statusbar to take up no vertical space what so ever and lay on top of the content (green)
How do I achieve this?
Answers in swift as well obj-c are very welcome
EDIT:
I have tried various versions of the following, the problem remains -.-
override func loadView() {
self.view = UIView(frame:UIScreen.mainScreen().bounds)
self.view.backgroundColor = UIColor.whiteColor()
self.navigation = UINavigationController(rootViewController: self.guideViewController!)
self.navigation!.navigationBarHidden = true
self.navigation!.setNavigationBarHidden(true, animated: true)
self.view.addSubview(self.navigation!.view)
}
override func viewDidLoad() {
self.automaticallyAdjustsScrollViewInsets = false
self.navigation!.automaticallyAdjustsScrollViewInsets = false
}
EDIT 2:
printing:
UIApplication.sharedApplication().statusBarFrame.size.height
after viewDidLoad returns 20
Updated :
Just add this in you ViewDidLoad method
self.automaticallyAdjustsScrollViewInsets = NO;
You can use hide navigation bar like
[self.navigationController setNavigationBarHidden:YES];
Hide status bar
// Hide status bar iOS 7 or later
- (BOOL)prefersStatusBarHidden
{
return YES;
}
Look at this site: https://developer.xamarin.com/recipes/ios/content_controls/navigation_controller/make_the_nav_bar_disappear/
This site says that "The behavior is slightly different depending on whether the Nav Bar is opaque or translucent"
I hope it is helpful.
[self.navigationController setNavigationBarHidden:YES animated:animated];
I know the question has already been answered but I was having the same issue when hiding a navigation bar then using a UIScrollView in the view.
I fixed it programmatically using:
self.edgesForExtendedLayout = UIRectEdgeNone;
Or in interface builder by deselecting all of these:

UINavigationItem Prompt Issue

I'm having a problem with the prompt on a UINavigationItem that I just can't resolve...
I have a master and a detail view controller. When I push from the master to the detail a prompt is shown on the detail view controller:
However, when I pop back to the master view controller, the view isn't resized and the window shows through (the window has been coloured red):
This only happens on iOS7, on iOS6 the view resizes as expected.
I've tried a few things such as setting the prompt to nil in viewWillDisappear or viewDidDisappear but nothing seems to fix it.
If I set the navigation bar in the navigation controller to translucent it does fix this - unfortunately that's not an option.
I've created a very small example project here which demonstrates the issue: https://github.com/InsertWittyName/NavigationItemPrompt
Thanks in advance for any help!
A solution I can think of is to subclass the UIView of the master, and implement viewDidMoveToSuperview to set the frame of the view to be from the navigation bar's height to the end of the superview. Since the navigation bar is not translucent, your job is easier, as you don't have to take into account layout guides and content insets.
A few things to notice. When pushing and popping, the system moves your view controller's view into another superview for the animation and then returns it to the navigation controller's private view hierarchy. Also, when a view goes outside of the view hierarchy, the superview becomes nil.
Here is an example implementation:
#interface LNView : UIView
#end
#implementation LNView
- (void)viewDidMoveToSuperview
{
[super viewDidMoveToSuperview];
if(self.superview != nil)
{
CGRect rect = self.superview.bounds;
rect.origin.y += 44;
rect.size.height -= 44;
[self setFrame:rect];
}
}
#end
This is not a perfect implementation because it uses a hardcoded value for the navigation bar's height, does not take into account a possible toolbar, etc. But all these you can add as properties to this view and in viewDidLoad, before it starts going into the view hierarchy, set the parameters according to your needs.
You can remove the prompt when the user taps the back button, like this
override func willMove(toParentViewController parent: UIViewController?) {
super.willMove(toParentViewController: parent)
if parent == nil {
navigationItem.prompt = nil
}
}
The problem exists whether your nav bars are opaque or translucent. It sucks that Apple has allowed this heinous bug to plague us for over three years now.
All of these solutions are hacks. My solution is to either A) NEVER use prompts, or B) use them in every single view even if you have to set them to "".
You've given the answer yourself - brilliantly. It's a bug, but checking Translucent avoids the bug. Therefore the solution is to check Translucent and then compensate so that the nav bar looks the way you want.
To do so, make a small black rectangle image and include it in your project. Set the background image of the nav bar to this image. Check Translucent. Problem solved! The nav bar is now black opaque in appearance, but it no longer exhibits the bug.
Swift version:
class PromptViewSideEffect: UIView {
override func didMoveToSuperview() {
super.didMoveToSuperview()
if let superview: UIView = self.superview {
let rect: CGRect = superview.bounds
rect.origin.y += 44
rect.size.height -= 44
self.frame = rect
}
}
}

Strange UISearchDisplayController view offset behavior in iOS 7 when embedded in navigation bar

I am building an iOS 7-only app. I am trying to set a UISearchDisplayController into the navigation bar.
I have it set up like this: In the storyboard, I added a "Search Bar and Search Display Controller" to my view controller's view, and set it at (0,0) relative to the top layout guide. I set constraints to pin to left, top and right. (I played with the constraints, i removed them completely, it doesn't matter) On top of that I have my Table view. When I added the search bar to the view in the storyboard, it automatically setup outlets for searchDisplayController and searchBar delegate. In code I have self.searchDisplayController.displaysSearchBarInNavigationBar = YES; I have two problems:
1) Without any buttons showing for the search bar (Interface builder -> select search bar -> Options: none selected) the search bar is in the middle of the screen:
If I click on the navigation bar, it starts editing the search bar:
notice also that the dark overlay appears to be offset from the navigation bar. It seems to me that the space is the same height as the navigation bar. Like it has been shifted down by that much. Also, when it displays the search results, the top of the content view is shifted down by the same amount (more pictures follow), which brings me to the second problem.
2) I messed around with it for a while and decided to check the option to have it show the cancel button. Now I have the search bar embedded in the nav bar correctly, but the overlay is still shifted down:
Again, when the search results table view appears, it is shifted down by the same amount (notice the scroll bar on the right side):
Even more bizarrely, I set a border on the search display controller's tableview layer, and it appears correct:
I have never used the UISearchDisplayController before and I unfamiliar with how to set it up, but functionally it works fine. I have read some other similar posts but the only advice is to hack it up by adjusting frames and setting manual offsets. I'd prefer to know what is causing this, is it a bug? Something I'm doing wrong? If it's a bug I can wait for a fix. It seems like such a basic thing that a thousand people must have done without any problem so I feel like I'm not setting it up correctly somehow. Thanks for you input.
I remember running into the same exact problem that you are observing.There could be a couple of solutions you can try.
If you are using storyboards
You should click on the view controller or TableView Controller which you have set up for your tableview and go to its attribute inspector and look under ViewController section and set the Extend Edges section to be under Top Bars.
If you are not using storyboards you can manually set the settings using the viewcontrollers edgesForExtendedLayout property and that should do the trick. I was using storyboards.
In my case, using storyboards, I had to check both Under Top Bars and Under Opaque Bars and leave Under Bottom Bars unchecked.
In my case, I actually had to uncheck all the Extended Edges boxes (essentially the same as programmatically setting Extended Edges to UIRectEdgeNone I believe) in my Storyboard in order to stop my search bar from offsetting itself. Thank you guys!
definesPresentationContext = true
override func viewDidLoad() {
super.viewDidLoad()
searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
searchController.hidesNavigationBarDuringPresentation = false
searchController.dimsBackgroundDuringPresentation = true
searchController.searchBar.searchBarStyle = UISearchBarStyle.Prominent
self.tableView.tableHeaderView = searchController.searchBar
definesPresentationContext = true
or see UISearchBar presented by UISearchController in table header view animates too far when active
My problem was just Adjust scroll view inserts. After change to false I didn't have problem
I had a same problem. And I solve this issue with adding view object under the tableview.
Add new ViewController on the Storyboard
Drag TableView to the new VC
Drag Table Cell to the TableView
Make a Connection for TableView DataSource, TableView Delegate to the new VC
I had very similar behavior happening. For me, the solution was to uncheck Extend Edges Under Top Bar in the storyboard settings for the parent view controller (I've turned off transparent navbars, not sure if that effects anything). If you're not using storyboard, you have to set [UIViewController edgesForExtendedLayout].
From the Apple docs:
This property is only applied to view controllers that are embedded in containers, such as UINavigationController or UITabBarController. View controllers set as the root view controller do not react to this property. Default value is UIRectEdgeAll.
Unfortunately none of the above solutions worked for me, I'm using a UITableViewController.
This link helped:
http://petersteinberger.com/blog/2013/fixing-uisearchdisplaycontroller-on-ios-7/
I put the code below for convenience:
static UIView *PSPDFViewWithSuffix(UIView *view, NSString *classNameSuffix) {
if (!view || classNameSuffix.length == 0) return nil;
UIView *theView = nil;
for (__unsafe_unretained UIView *subview in view.subviews) {
if ([NSStringFromClass(subview.class) hasSuffix:classNameSuffix]) {
return subview;
}else {
if ((theView = PSPDFViewWithSuffix(subview, classNameSuffix))) break;
}
}
return theView;
}
- (void)correctSearchDisplayFrames {
// Update search bar frame.
CGRect superviewFrame = self.searchDisplayController.searchBar.superview.frame;
superviewFrame.origin.y = 0.f;
self.searchDisplayController.searchBar.superview.frame = superviewFrame;
// Strech dimming view.
UIView *dimmingView = PSPDFViewWithSuffix(self.view, #"DimmingView");
if (dimmingView) {
CGRect dimmingFrame = dimmingView.superview.frame;
dimmingFrame.origin.y = self.searchDisplayController.searchBar.frame.size.height;
dimmingFrame.size.height = self.view.frame.size.height - dimmingFrame.origin.y;
dimmingView.superview.frame = dimmingFrame;
}
}
- (void)setAllViewsExceptSearchHidden:(BOOL)hidden animated:(BOOL)animated {
[UIView animateWithDuration:animated ? 0.25f : 0.f animations:^{
for (UIView *view in self.tableView.subviews) {
if (view != self.searchDisplayController.searchResultsTableView &&
view != self.searchDisplayController.searchBar) {
view.alpha = hidden ? 0.f : 1.f;
}
}
}];
}
// This fixes UISearchBarController on iOS 7. rdar://14800556
- (void)correctFramesForSearchDisplayControllerBeginSearch:(BOOL)beginSearch {
if (PSPDFIsUIKitFlatMode()) {
[self.navigationController setNavigationBarHidden:beginSearch animated:YES];
dispatch_async(dispatch_get_main_queue(), ^{
[self correctSearchDisplayFrames];
});
[self setAllViewsExceptSearchHidden:beginSearch animated:YES];
[UIView animateWithDuration:0.25f animations:^{
self.searchDisplayController.searchResultsTableView.alpha = beginSearch ? 1.f : 0.f;
}];
}
}
- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller {
[self correctFramesForSearchDisplayControllerBeginSearch:YES];
}
- (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller {
[self correctSearchDisplayFrames];
}
- (void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller {
[self correctFramesForSearchDisplayControllerBeginSearch:NO];
}
- (void)searchDisplayController:(UISearchDisplayController *)controller didShowSearchResultsTableView:(UITableView *)tableView {
// HACK: iOS 7 requires a cruel workaround to show the search table view.
if (PSPDFIsUIKitFlatMode()) {
controller.searchResultsTableView.contentInset = UIEdgeInsetsMake(self.searchDisplayController.searchBar.frame.size.height, 0.f, 0.f, 0.f);
}
}
Go to storyboard.
Click on the view controller.
Go to attribute inspector under the ViewController section.
Set the Extend Edges section to be Under Top Bars and Under Opaque Bars.
Make sure to un-check Under Bottom Bars.

Resources