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

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.

Related

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

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.

How to make a view controller adopt the same size as its distant ancestor's container view?

This will be easiest to explain with a diagram:
Here the initial view controller has a container view which contains the tab bar controller (note that the red bar at the top is a view, the initial view controller is NOT a navigation controller).
Any views displayed by the tab bar controller will occupy the same dimensions as the container view. Therefore when the blue VC is displayed the screen will continue to show the red view.
If when the button on the blue VC is clicked the green VC is presented modally and it occupies the full screen and thus covers the red view.
My question is, is there a simple way to make the green view controller occupy the same dimensions as its grand parent's container view so that the red view will be visible when the green VC is displayed.
(By simple, I don't want to do anything involving strong coupling such as the green vc obtaining the explicit dimensions of the container view and setting its dimensions to match. I'm hoping there's a setting in the storyboard or a different way of presenting the vc which will result in it automatically adopting the same size as its parent).
Yes I know the intitial view controller could be a navigation controller, we don't need to discuss why its not.

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.

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.

(Swift) Adding Pinned Navigation Bar to UICollectionView

I have a UICollectionView that scrolls with a bunch of images and I want to have a pinned Navigation Bar on the top that stays there even as you scroll. I moved the cell down in the UICollectionView in order to make room for a navigation bar and I dragged one into the View. I can see it in my story board however it is just a black view when I run the app. Can anyone please show me how to make this nav bar appear and how to make it stay pinned at the top even as you scroll. Thank you so so much. (I tried to attach photos of my problem but it says I do not have enough reputation to post images) I hope you guys are able to understand my problem and direct me in a way in which I could add a navigation bar that stays pinned on the top of a CollectionViewController
Drag a navigation controller into your storyboard. You probably want to position it just to the left of the view controller that has the collection view.
Delete the view controller that Xcode automatically attaches to the navigation controller.
Right click on the navigation controller and drag from root view controller over to your view controller where you have your collection view.
If necessary, move all segues that went to the collection view to the navigation controller instead.

Resources