Setting a UINavigationItem.titleView = MyLogoView for all UINavigationViewController children UIViews - ios

My question is technically a duplicate of this SO: How do I set custom navigation bar(title + titleView) for all navigation controllers and view controller?
The base class answer in the link above is my current solution as I will explain below. One problem with this solution though is that it makes my company logo image titleView disappear and reappear for a second with every segue, I am looking to keep the logo visible through all navigation transitions.
I am using a company logo in the center of my UINavigationBar. Currently, for any child UIView of my UINavigationViewController, I add a UINavigationItem outlet in the Xcode 7 Storyboard by CTRL Dragging to my Swift ChildViewController and always use the same ID:
#IBOutlet weak var uiNavItemTitle: UINavigationItem!
I then delete that above Xcode generated line because I have the same line in MyBaseViewController that ChildViewController inherits from. Now I can set the logo one time in MyBaseViewController and every ChildViewController inherits from MyBaseViewController, this code is in MyBaseViewController:
#IBOutlet weak var uiNavItemTitle: UINavigationItem!
override func viewDidLoad() {
super.viewDidLoad()
// MARK: - UINavigationController Defaults
uiNavItemTitle.titleView = CoreUtility.LogoForUINavBarGet()
self.navigationController?.navigationBar.topItem?.title = "";
self.navigationController?.navigationBar.tintColor = UIColor.whiteColor()
}
What is becoming an issue with this solution is that for every ChildViewController in my UINavigationViewController stack of segues, I have to add a UINavigationItem outlet and make sure I inherit MyBaseViewController. Some of my navigation segue views deeper in the navigation chain should not really inherit from this MyBaseViewController though.
Another issue with my solution is that the company logo disappears and reappears a second later for each segue to a new UIViewController
I can create another level to the hierarchy of inheritance is one possible solution.
But my UINavigationItem.titleView is always the same company logo for every child UIViewController segued to.
Do I have to add a UINavigationItem to every UIViewController?
Or is there an "Application" level way such as using, in my AppDeletgate.application():
//MARK: - UINavigationBar.appearance
UINavigationBar.appearance().tintColor = UIColor.whiteColor()
UINavigationBar.somethingForTitleView
Where somethingForTitleView becomes code to set a Application wide Navigation Bar titleView to my logo View.

Related

What is best approach to creating a persistant UIView nav bar in a UITabBarController?

I've added a custom UIView to my base UITabBarController. I start by hiding the default tabBar. The viewdidload looks like this in UITabBarController:
override func viewDidLoad() {
super.viewDidLoad()
//hide default tab bar
self.tabBar.isHidden = true
tabBarArea.frame.size.width = self.view.frame.width
tabBarArea.frame.origin.y = self.view.frame.height - tabBarArea.frame.height
self.view.addSubview(tabBarArea)
}
That works well. The tabBarArea is defined in the storyboard as a custom view for the UITabBarController. The custom view sits between the First Responder and the Exit icons in the top bar.
Now, the problem is that the UITabBarController will disappear as soon as we load a child view controller and this custom UIView area will vanish with it.
Is there a way to make this root custom view always present even when child view controllers are loaded in?
Thanks for input. I like the idea of this custom UIView area but this approach needs refinement. I also don't need it to be a traditional UITabBarController with tab bar items, etc. I'd like to break out of that mold and just have custom UIButtons are whatever in this view area.

How to overlap navigation bar by adding view in swift?

I want to make a custom side bar by adding a new view to the view controller, the side bar will be in the yellow color background. I want my side bar also to overlap the navigation bar/item (green background color) in my view controller. but the navigation bar/item seems can't be overlapped by my side bar view, it seems only overlap the main view.
I tried to find the answer in stackoverflow, I find this Overlap navigation bar on ios 6 with other view, but the answer is on the Objective-C, I can't read Objective-C :(
What should I do to overlap navigation bar/item ? here is the screenshot of my view controller
I embed the navigation controller like this
There are plenty of implementations of slide-over or drawer containers.
What you need to do to get above the navigation bar is CONTAIN the navigation controller inside another view controller.
The stack would look like this.
MasterViewController
UINavigationController
RootViewController
Menu
See this one here:
Swift version of MMDrawerController
You can do this by changing your UIViewController hierarchy. For this you'll need three view controllers. First will contain everything, let's call it MasterViewController; second—your main content with navigation bar; and third—drawer.
In MasterViewController instantiate child view controllers and add them to your view controller hierarchy in viewDidLoad().
final class MasterViewController: UIViewController {
override func viewDidLoad() {
let drawerViewController = DrawerViewController()
let mainViewController = MainContentViewController()
let navigationController = UINavigationController(rootViewController: mainViewController)
addChildViewController(drawerViewController)
addChildViewController(navigationController)
view.addSubview(navigationController.view)
view.addSubview(drawerViewController.view)
}
}
Now you have navigationController.view that you can place or animate anywhere within view.

Fixed Navigation Bar For Different View Controllers

I am trying to implement a navigation bar whose contents persist between different view controllers. For example, I have the following functionality right now:
Non Persistent Navigation Bar
I have set an imageView as the titleView of the navigation bar.
The titleView of the navigation bar transitions along with the view controller here (the image shows some animations by fading in and out). But I would like it to stay hooked onto the top of every screen without any transitions. This would mean that only the part of the view below the navigation bar would show the transition from one view controller to another.
Is that possible in Swift?
Yea that is possible. What you can do is have a container view controller, which can have your navigation bar along with a content view controller.
Now each time you open a new VC, push the new VC on the containerVC's contentVC.
For ex:
let containerVC = self.parentViewController?.containerViewController()
if let _ = containerVC {
containerVC.pushContentViewController(newViewController)
}
Attaching layout screenshot for more understanding.
So if you check here, the Root Container is the view where you can add your new VC as a child VC.
You can do this by changing your UIViewController hierarchy. For this you'll need three view controllers. First will own your UINavigationBar and UIView where other two UIViewController's views will live.
Let's call one with the navigation bar MasterViewController, and other two—ViewControllerA, ViewControllerB respectively.
Somewhere in MasterViewController instantiate child view controllers and add them to your view controller hierarchy. For simplicity's sake let's do everything in viewDidLoad() but you can do do this anywhere you deem it necessary. You could even load view controllers lazily as user demands them.
final class ViewControllerA: UIViewController { }
final class ViewControllerB: UIViewController { }
final class MasterViewController: UIViewController {
var navigationBar = UINavigationBar()
override func viewDidLoad() {
view.addSubview(navigationBar)
let a = ViewControllerA()
let b = ViewControllerB()
addChildViewController(a)
addChildViewController(b)
view.addSubview(a.view)
// you are ready for transitions from a.view to b.view when necessary
}
}
Now you can do transitions from a.view to b.view (and back) and it will affect nothing in master view (which has the navigationBar).
It is important to note that view hierarchy and view controller hierarchy are not liked in any way and you are responsible for managing both.

UITabBarController inside master of UiSplitViewController

I want to achieve the same flow as Facebook messenger app, with a tab bar controller inside the master view. See
Ive done exactly as described in this answer
Create a TabBar Controller with a Master-detail template?
However! It does not work correctly on iPhone, only on iPad. On iPhone, the navigation backwards does not work. The detail pane opens up just like a modal seque with no possibility of moving backwards. What could be the error here? Is this even possible to achieve with standard uisplitviewcontroller? I have tried embedding navigationcontroller in tabbarcontroller also (making navigationcontroller as root in master view), then it works for iPhone but not iPad.
I ended up getting around this by not using a UITabBarController, instead creating a CustomTabBarController which inherits from UIViewController. The custom controller has a UITabBar at the bottom of its view, and multiple other UIViewControllers embedded in Container Views. The custom controller sets the isHidden property to true for of all of the embedded view controller except the one which corresponds to the selected tab.
The following is a simple example with two tabs, identified by their tag:
class CustomTabBarController: UIViewController, UITabBarDelegate {
#IBOutlet weak var tab1View: UIView!
#IBOutlet weak var tab2View: UIView!
#IBOutlet weak var tabBar: UITabBar!
override func viewDidLoad() {
tabBar.delegate = self
}
func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
tab1View.isHidden = item.tag != 1
tab2View.isHidden = item.tag != 2
}
}
This custom controller should be set to the root of a UINavigationController, which itself should be set as the master controller of the Split View Controller:
This setup works for both iPad and iPhone:
There are a few drawbacks to this method:
The custom tab controller is less easy to work with - adding a new tab requires that you add another embedded view and connect it to an outlet in the controller.
Setting the navigation item's title and left and right bar button items must be done within the custom tab bar controller, upon tab selection.
This method uses (I think) more memory than a regular UITabBarController, since all of the child view controllers are loaded as soon as the app loads, rather than when they are first shown.
This setup will lead to the tab bar being hidden when detail is shown in (portrait) iPhone mode. This was what I wanted, and is the behaviour in the Facebook Messenger app too, but if you want the tab bar to be permanently visible, this method won't do it.

Insert subview behind TabBar from child view of TabBarController

I have TabBar with 2 tabs. At some point, from either of the 2 tabs, I want to add a view that is visible on both tab views but behind the TabBar.
So I thought, insert a subview into the TabBarController but below the TabBar.
This works fine in principle and I have the view behind the TabBar but now covering my 2 tabs as I wanted. However, it doesn't actually load. Just its background loads and only viewDidLoad() is called, not viewWillAppear() or any others.
I have also tried calling addChildViewController(myVC) on the TabBarController which has no effect, and also manually calling viewWillAppear() on the view controller I add which also has no effect (and I'm also dubious about whether manually calling viewWillAppear() is permitted or not?).
Is what I'm trying to do possible? What am I missing? Or should I be attempting this some other way?
For some reason, when inserting a subview into a UITabBarController behind it's UITabBar, although the view is visible to the user, the system itself seems to think it is not and so although viewDidLoad() is called, viewDidAppear() and subsequent methods are not.
However, adding a subview above the UITabBar seems to work fine. So I solved this by adding my own new UITabBar as a subview to the UITabBarController (set up basically exactly as the default one would be) and then removing the UITabBarController's default UITabBar.
Then when later inserting my view into the UITabBarController, I insert it as I was doing originally but instead below/behind my custom UITabBar and it seems to load fine.
There is no need to remove and recreate the tabBar. What you need to do is after you insert your custom view, you can then bring the tabBar to the front again.
//bring the tabBar to the front after inserting new view
self.view.bringSubview(toFront: self.tabBar)
This would be a good way:
Add the function below and call it in viewDidLoad of your initial VC. It unwraps your tab bar controller instance (which is optional), and then inserts the view you always want visible just below the tab bar.
private func setupAlwaysVisibleView() {
guard let tabBarController = self.tabBarController else { return }
tabBarController.view.insertSubview(alwaysVisibleView, belowSubview: tabBarController.tabBar)
}
Avoid using optionals for tabBarController or removing current tabBar. Simple add your view below tabBar view. Swift 5, XCode 11.
class TabBarController: UITabBarController {
#IBOutlet var instructionsView: UIView!
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.view.insertSubview(instructionsView, belowSubview: self.tabBar)
}
}
you can also do this inside the init() method for your UITabViewController:
view.insertSubview(alwaysVisibleView, belowSubview: self.tabBar)
no need to dispatch to another method if you are using a subclass of UITabViewController.

Resources