Is it *possible* to make your own Tab Bar Controller? - ios

I have a project where our tab bar has a big middle button (that extends above the tab bar) and other custom behaviors including a badge icon and colored labels.
I got "smart" and decided to just write my own tab bar and tab bar controller to go with it. The problem I've run into is that when one of the tabs is wrapped in a UINavigationController, that view always takes up the whole screen (you can't capture a UINavigationController into a small subview) and so I have to manually inset the content on those views.
Is there a smart way to handle this? It feels gross to just cut the content short on each screen by 100 points...that doesn't feel right at all.
What approach should I take...or should I just automate the content insets programmatically?

A tab bar controller is just a scroll view with a view at the bottom that toggles between the scroll view's offset. I assume you want the tab bar controller to be at the root of your app, so in the root view controller, add a UIScrollView.
Then add the views of the view controllers (the tabs) to that scroll view, and anchor them appropriately so that the scroll view scrolls. Make the heights and widths of these view controllers full screen. Before you add them to the scroll view, you must create a parent-child relationship between the root view controller and its tabs.
self.addChildViewController(tabOneViewController)
tabOneViewController.view.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(tabOneViewController.view)
tabOneViewController.didMove(toParentViewController: self)
tabOneViewController.delegate = self // so that your tabs can communicate back to the controller
// add constraints
Each of these view controllers will ideally be or contain the navigation controller for that section.
Then just add the tab bar to the view of the view controller, not to the scroll view (add this after the scroll view so that it sits above the scroll view). This tab bar is just a regular UIView, most often anchored to the view controller's bottom safe area. Because its a part of the view controller's view, and not the scroll view, it has no impact on the content behind it.
The benefit of a custom tab bar setup like this is that you can navigate between tabs on tap or by pan gesture. To navigate between tabs by tapping on the buttons in the tab bar, simply change the scroll view's content offset:
// this would move to the third tab
scrollView.contentOffset = CGPoint(x: view.bounds.width * 2, y: 0)
Add your bells and whistles and you're set.

Related

In a container view, a navigation controller's navigation bar not resizing to include status bar

I have created an application which needs to have a bar above the navigation bar and other views. To accomplish this, I am using a view controller with a view for the top bar, and then a container view for everything else. Sometimes, the top bar needs to be hidden. I'm using autolayout to hide the top bar (set its height to 0), and the container view expands to fill the screen (container top equal to the top bar bottom). The container view contains a navigation controller because I need a navigation bar below the top bar sometimes. When I start the app, this all works fine as shown below:
As you can see, the navigation bar stays the desired height, which is expanded to include the status bar
However, when the top bar is tapped, I use a segue to present (not push) a view controller from my root view controller (not the container), and then I look at the same screen with the navigation bar, the navigation bar is no longer extended and it overlaps the status bar as seen below:
Why would presenting a view controller break this? And then how could I rectify this or prevent it?
One possible solution I could do is present a view controller from within the container view, that works, I would just have to set the current view controller in the container to a delegate of the root controller, so that when the top bar is tapped, it tells the view controller in the container to present the new view controller. This would not be my first option however, especially if there are other scenarios which cause this problem.
Thanks for any help!
You need to turn automaticallyAdjustsScrollViewInsets off for all of your child view controllers and manage the insets (or setup so they aren't required) yourself. By default automaticallyAdjustsScrollViewInsets is on for all view controllers (which is what you want for 'full screen' presented VCs.
At the moment you see controllers almost randomly updating to reorganise themselves for the scroll insets as the VC hierarchy changes.
I'd probably turn automaticallyAdjustsScrollViewInsets off for all VCs (apart from root) and change your header view so that it's full height or status bar height (which should be the length of the topLayoutGuide of the root VC). When collapsed to status bar height your header view could also change colour to match that of the current top VC.

How to create a view above navigation bar or other screen content?

I would like to have a view above the navigation bar, or above any screen content if there isn't a navigation bar on that screen, so that it essentially reduces the height of everything else and doesn't cover any content. I also would like this view allow interaction (i.e. if its tapped, it would do something).
I have tried
UIApplication.sharedApplication().keyWindow?.addSubview(view) but that just overlays the view.
Here is a visualization:
Don't think of it in terms of above, think of it as beside - a sibling view.
So, create your own root view controller with that view and a container view below it, then add your 'normal' root navigation controller (or whatever) as a child view controller into the container view.

Adding a view above UINavigationBar

I'm trying to add a custom view above the navigation bar as displayed on the following image .
What I've tried so far is to add the view as a subview of the navigation bar - Did not work
Add the custom view first on Interface builder and then add a navigation bar manually - This seems to mess up with my navigation as the default navigation controller has it's own navigation bar.
Is this a bad approach on its own ?
If this is a view that will appear above all navigation bars in the app, why not use a Container View?
Make the Container View fill the screen, but give it a 20 point top margin to fit your custom green view. Then when you add your main view controller (wrapped in a navigation view controller) to the Container View, it will show your green view above it.
If you don't want your margin in a particular screen, do the following:
Add a constraint to the top margin and add an outlet to it so you can modify the constraint's constant in code.
Then, in any screens where you don't need the margin, access the parent view controller view and set the constraint's constant to zero.
let myParentViewController = self.parentViewController as? MyParentViewController
myParentViewController.myTopMarginLayoutConstraint.constant = 0
Don't forget to reset it to 20 (or whatever) when you go to a screen where you need the top margin again.

iOS UIPageViewController child view under Bottom Bar

I had an UIPageViewController embedded in a NavigationController embedded an TabBarController.
I supposed every child view of the UIPageViewController fits the size within the UITabBarViewController.
The first child view looks fine:
Switch to the next (vertically), it's view suddenly resizes and the view length expands over the bottom bar:
Actually it's not under the bottom bar but clipped to that size (which means if you pull up the view you still cannot see the whole but the cut text).
I did unchecked every related view controller's Under Bottom Bar & Adjust Scroll View Inset but nothing works.
Any suggestion would be appreciated.
Try this in table view controller viewDidLoad() method.
self.extendedLayoutIncludesOpaqueBars = NO;
OR
you can set property in Interface Builder:
Uncheck Extend Edges: Under Bottom Bars, Under Opaque Bars.

Can I place a UIView the current Navigation Controller?

How can I place a UIView overtop of a Navigation Controller? Is this possible without making my own custom navigation bar and custom tab bar controller out of UIViews?
Let's say I have a UITabBarController and I want to present a blur view overtop of the entire thing. For the blur view, I'm using the UIVisualEffectView. But i want the blurview to take up the entire screen including the top navigation bar and the bottom tab bar. If I push a new view controller, that will take up the entire screen, but then I can't see through it to what's underneath (the tab bar controller's contents).
I could simply hide the navigation bar and tab bar when I animate in the blur view, but that looks awkward because you see the content in the collectionview shift because the navigation bar is hiding... I'd rather not see that shift in the content when the blurview comes up.
Here's a UITabBarController with stuff in it.
I want a blur view to cover everything and to be able to see through to the entire UITabBarController and the stuff underneath.
One way is to add the UIView as a subview of the key window. See this post for how to get the key window. However, it's generally best to keep to your own view hierarchy, so...
Another way might be to present a new view controller as a fullscreen modal, and apply the blur/transparency to that modal view.

Resources