I use UISearchViewController to control my app's search stuff. I saw there's a property called hidesNavigationBarDuringPresentation for handling the navigationBar's visibility, but what I wanna do is to hide tabbar during presentation, I can't find any properties to do this.
Any work-around?
You're right that there's no property for explicitly showing & hiding the tab bar, but it's easy enough to implement yourself:
Make your view controller (not the UISearchController) implement UISearchControllerDelegate.
Assign your view controller to the search controller's delegate property.
Implement willPresentSearchController() (or didPresentSearchController()) and presentSearchController() to hide your tab bar. (The former is called when the search bar is automatically shown; the latter is called when you show it manually.)
Implement willDismissSearchController() (or didDismissSearchController) to show it again.
Note that if your implementations simply toggle the search bar's hidden property, then the bar won't animate in and out; you'll have to do your own animation.
It may be a good idea for your implementations to check the value of hidesNavigationBarDuringPresentation so that your tab bar is shown and hidden only when the navigation bar is.
Related
Scenario:
We have a tab bar controller in the app.
Only one view controller has a different color style for the StatusBar, let's call this view controller VC1.
So I have added logic in VC1, viewWillAppear set the wanted StatusBar Color, viewWillDisappear reset the default StatusBar Color.
Issue:
Most of the time, different tabs have different view controllers, this is no issue of the status bar color changing.
But In one case, I will have VC1 shown in two tabs, in this case, when I switch tab, viewWillAppear got called first, which means the reset StatusBar style got called later, so after switching the tab, the StatusBar Color is wrong.
Is there a way to solve this? It seems the view controller life cycle is wrong in this scenario.
Look at UITabBarControllerDelegate. Using that, you can take action based on which tab is selected - such as changing the color of the StatsBar - instead of doing that inside the VC.
You use the UITabBarControllerDelegate protocol when you want to
augment the behavior of a tab bar. In particular, you can use it to
determine whether specific tabs should be selected, to perform actions
after a tab is selected, or to perform actions before or after the
user customizes the order of the tabs.
ref: https://developer.apple.com/documentation/uikit/uitabbarcontrollerdelegate
How can I implement hide on swipe programmatically? the reason why I don't want to use the Hide Bars on swipe option from the attributes menu is because I came across a problem. When enabled, the app will hide the navigation bar, as well as the toolbar if the user scrolls down the content view, and the bars will appear when the user swipes back up. I don't want this change to apply to all the navigation bars of the entire app. I want to be able to just hide one navigation bar. I did gave this an attempt, I set the hidesBarsOnSwipe property to true as shown in the code below
navigationController?.hideBarsOnSwipe = true but I came across other problems, I tried placing my code above the viewDidLoad method in the ViewControllers where this feature will be enabled and I set the property to false on the ones I don't want to this featured to be enabled.
My problem: I can't hide the navigation bar after navigating back to the view controller with the false property
I don't understand what I'm doing wrong, any suggestions?
Instead of putting your code in viewDidLoad(), put it in viewWillAppear() -- that ensures it's called every time your View Controller comes on screen, since with Navigation Controllers, the viewDidLoad() method isn't always called when view controllers are popped. Also make sure to explicitly mention the preffered setting for each view controller -- i.e. navigationController?.hideBarsOnSwipe in the viewWillAppear() of each of your View Controllers.
Hope this helps.
Swift 4
navigationController?.hidesBarsOnSwipe = false
I followed this blog post that explains how you can implement a custom UINavigationBar that has an increased height, if for example you wanted to put additional ui elements in the nav bar underneath the rest of the bar content that will persist between navigation on the stack. This code works really well in the case where you always want it to be that increased height.
In my app, I need to start the navigation bar at its default height, then increase it later, adding more content, after the user performs a given action. Very similar to the song info and controls in the iTunes Store:
So I put some checks in place to not reposition anything if a BOOL property is NO. When I set it to YES, I call [self setNeedsDisplay] which will call layoutSubviews to position everything appropriately based on that boolean value. sizeThatFits is also called and I return the proper height.
The problem is, I can't call [self setTransform:CGAffineTransformMakeTranslation(0, -(NavigationBarHeightIncrease))]; in initialize. Instead I call that at the same time I change the boolean value to YES. Because of this, all of my elements are moved up that amount. But if I don't call setTransform, the elements in the nav bar are in the proper position, but the bar itself is positioned too far down, so that the custom view I've added to the bar is shown overtop the view controller's view - it bleeds out, and the extra space I added is black not the navigation bar's background color.
If I call setTransform in initialize, when the height is the default height, the elements are moved up when they shouldn't be.
So, how can I properly dynamically change the height and positioning of a UINavigationBar subclass?
As suggested in the comments, to achieve the behavior where a custom navigation bar (not subclassing the native control) persists across pushes and pops of controllers in a navigation controller, you'll need to have a single controller with the custom navigation bar and then a single embedded view that resolves to a UINavigationController with its view controllers underneath. Then, it will also be necessary to set the navigation controller's delegate to the root controller so that the title and other properties can be updated as the sub-controllers are pushed and popped. I've provided a screenshot below of what the storyboard version of this might look like:
An option is to create a UIViewController in storyboard which has only the control view you wish to show below the navigation bar with everything else transparent. The advantage here is you design this using the normal tools. Use constraints to place it just below the navigation bar and to set the heights, widths etc of your views.
When you wish to show the control, you can create an instance of this UIViewController and remove the content view from it and add it to the view hierarchy of what is on screen.
There are two options for inserting the extracted base view:
If you add this control view to the view controller at the top of
the navigation stack (what is on screen), it would be covered when
you push on a new controller. This is not what you said you wanted.
If you add this control view to self.navigationController.view, then
it will persist across pushes and pops. This is what you said you wanted.
I use this approach to provide popup help bubbles to describe what is on screen. Depending on whether I use option 1 or 2, I can persist help across multiple pushes/pops.
I got the idea from this tutorial which describes the general approach: http://blog.typpz.com/2013/12/09/ios-sdk-create-a-pop-up-window/
That link provides a full code example on how to bring up the view and remove the view.
This would let you design it in IB, present and dismiss it as required and persist it across navigation sequences.
Hope this helps.
I am confused about the relationship of navigation controller and content view controllers. In storyboard, navigation bar is under the navigation controller, so I linked it to the NavigationController class and then customized the navigation bar in the viewDidLoad function. However, since different content views will have different navigation bar, like different bar buttons, how can I realize this? Just some basic ideas are good enough. My guess is that I need to specify specific bar buttons in specific content view controllers, but since the navigationBar property is in NavigationController class, how can I refer to it?
I want to hide the title of the navigation bar and make the bar only show some custom buttons (I know toolbar may match it better, but I have other reasons to adopt navigation bar). Please tell me how to hide the title in detail and swift language is preferred.
1) Every ViewController instance has a navigationController property, it' just an optional. To set the bar buttons, you'll want to use navigationItem. So to specify bar buttons you either do so in Interface builder per view controller, or just or do something like this in viewDidLoad
let navBarButton = UIBarButtonItem()...set up bar button
self.navigationItem?.leftBarButtonItem = navBarButton
2) Hiding the title is trivial:
self.navigationItem?.title = ""
The documentation for the toolbar property in UINavigationController says:
This property contains a reference to the built-in toolbar managed by the navigation controller. Access to this toolbar is provided solely for clients that want to present an action sheet from the toolbar. You should not modify the UIToolbar object directly.
I can understand why I shouldn't modify the toolbar's visibility or items, because UINavigationController provides an interface to do that. But I've added a button that, when tapped, causes the toolbar to animate offscreen. Why shouldn't I do this?
Must I instead create my own ToolbarNavigationController class that replicates everything UINavigationController does with the toolbar just sod, I can do what I want with the toolbar? Seems like a waste of effort when the UINavigationController already does what I want. Why on earth would the docs suggest I so severely limit what I do with it?
Three ways that having moved the navigation bar might confuse it:
If your app can be rotated, does it stay in the right place after rotation? When it returns to the screen, does it animate on from the right place?
If you display a search bar, the navigation bar animates itself off. If it's already been moved manually, does it know where it is?
If you push a viewController with hidesBottomBarWhenPushed set to YES, and return, does the navigationController put its toolbar back where it belongs?
On the other hand, how about calling UINavigationController setNavigationBarHidden:NO animated:YES - does that do what you want, while letting the navigation controller maintain control of its toolbar?
Edit: Sorry about misreading. Yes, you probably can do what you're asking, as long as you don't also do anything (like item 3 above) that mean the navigationController moves its toolbar around.
On the other hand, the behavior you want can also be achieved as follows:
For the viewController with the multiple toolbars, set its hidesBottomBarWhenPushed to YES.
Place all the toolbars that viewController needs on it, and have it take full control of their positions and visibility.
If the default toolbar has the same layout as the navigationController's own toolbar, this will create the odd visual effect of seeing the same set of toolbar items slide off and then on again, but everything else should work.
UIToolbar is inaccessible because it doesn't need to be accessible. It responds to +appearance just fine. In your case, you can access the properties of a readonly variable (look at CGRect!). If you need to animate a UIToolbar or UINavigatiomBar offscreen, set it's frame.center property equal to a CGPointMake in a UIView animation block.