Swift - Expand ViewController behind the TabBar - swift

I created three tabItems in UITabBarViewController which is pushed to another UINavigationController. One of the three tabItems is a UINavigationController, the other two are UIViewController. In order to make sure there is only one navigation bar is shown when it is in non-root viewController of the tabItem which is a UINavigationController, the parent UINavigationBar will be hidden.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let navigationC = self.navigationController, navigationC.viewControllers.count == 1 {
self.navigationController?.setNavigationBarHidden(true, animated: false)
self.parent?.navigationController?.setNavigationBarHidden(false, animated: false)
} else {
self.navigationController?.setNavigationBarHidden(false, animated: false)
self.parent?.navigationController?.setNavigationBarHidden(true, animated: false)
}
self.setupViewConstraints()
}
The issue here is, if I navigate to the 2nd UIViewController of the UINavigationController, then switch from UINavigationController to UIViewController and back to the UINavigationController, the bottom of the UINavigationController is moved up which should equal to the bottom of the UIScreen. If I navigate back to the root view of the UINavigationController, the bottom of the UINavigationcontroller is equal to the UIScreen which is correct.
How can I make sure all UIViewControllers' bottom in the navigationController is equal to UIScreen? It may due to there are two navigationBar in the non-root viewController of UINavigationController tabItem.
Below is the code I used to create UITabBarViewController:
override func viewDidLoad() {
super.viewDidLoad()
tabBar.tintColor = UIColor.fromHexString("0078d7")
tabBar.barTintColor = UIColor.white
let firstViewController = FirstViewController()
firstViewController.delegate = self
firstViewController.tabBarItem = UITabBarItem.init(title: "first", image: , tag: 0)
let secondViewController = SecondViewController()
secondViewController.delegate = self
secondViewController.tabBarItem = UITabBarItem.init(title: "second", image: , tag: 1)
let thirdViewController = ThirdViewController()
thirdViewController.delegate = self
thirdViewController.tabBarItem = UITabBarItem.init(title: "third", image: , tag: 3)
let initialNavigationController = UINavigationController(rootViewController: firstViewController)
initialNavigationController.navigationItem.title = ""
self.addChildViewController(initialNavigationController)
self.addChildViewController(secondViewController)
self.addChildViewController(thirdViewController)
self.navigateToLastVisitedViewController(navigationController: initialNavigationController)
}

In above viewDidLoad method of UITabBarViewController just make your tabBar translucent. This will allow you content viewController to lay beneath UITabBar object.
Swift
self.tabBar.isTranslucent = true
Objective-C
[self.tabBar setTranslucent:YES];
Same logic will be use in UINavigationBar case.

Related

Navigation Controller inside Tab Bar Controller is showing but Right Bar Button not showing - Swift 4 - Programmatic Approach

I'm still new to iOS Dev.
Goal: Create an iOS App with Navigation Bar (with .add as right bar button) at the top and Tab Bar at the bottom screen using Programmatic approach (not using storyboards and xib)
So I did almost everything here: https://developer.apple.com/library/archive/documentation/WindowsViews/Conceptual/ViewControllerCatalog/Chapters/CombiningViewControllers.html
But apparently it doesn't work (maybe because it is old? idk) and I'm also not comfortable configuring the App Delegate yet.
So what I have are these:
CompanyViewController as UIViewController
AssessmentViewController as UIViewController
TabViewController as UITabBarController, UITabBarControllerDelegate
I tried putting navigation controllers inside each VCs (navigationBar when I tap Tab Bar Items, which is expected - but the Title and Right Bar Button is NOT showing
I tried creating Swift file UINavigationController and named it NavigationViewController then added it to the TabViewController -> viewControllers but what happened was it was added to the tab bars at the bottom of the screen so it's not what I need and it looks like an ordinary tab not a navigation bar.
This is the last one I tried which displays Navigation Controller with its title but not its right bar button...
class TabViewController: UITabBarController, UITabBarControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let tabOne = CompanyViewController()
let tabOneBarItem = UITabBarItem(title: "Company", image: .none, tag: 1)
tabOne.tabBarItem = tabOneBarItem
let tabTwo = AssessmentViewController()
let tabTwoBarItem2 = UITabBarItem(title: "Assessment", image: .none, tag: 2)
tabTwo.tabBarItem = tabTwoBarItem2
self.viewControllers = [tabOne, tabTwo]
setUpNavigation()
}
func setUpNavigation() {
navigationItem.title = "Company Assessmentz"
self.navigationController?.navigationBar.barTintColor = colorLiteral
self.navigationController?.navigationBar.isTranslucent = false
self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor:colorLiteral]
self.navigationController?.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(selectorX))
}
#objc func selectorX() { }}
replaced this:
self.navigationController?.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(selectorX))
to this:
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .camera, target: self, action: #selector(selectorX))

My UIViewcontroller is not filling the entire screen?

I have a very simple app with two UIviewcontrollers. I want to dismiss one and present another one. However, when I do this (code below), the second viewcontroller does not fill the screen, instead it hovers over the top one and can easily get dismissed if you swipe from the top down (you can just about see the first viewcontroller at the top)?
VC-1:
#objc private func picksAction(){
print("picks button pressed")
let layout = UICollectionViewFlowLayout()
let viewController = GridPicksCollectionViewController(collectionViewLayout: layout)
let navController = UINavigationController()
navController.pushViewController(viewController, animated: true)
self.present(navController, animated: true) {}
}
Result:
Set modalPresentationStyle to .fullScreen:
navController.modalPresentationStyle = .fullScreen

TabBar controls the NavigationBar

I added 2 ViewControllers into a TabBar, but now, the TabBar's NavigationBar 'took over' each view's NavigationBar.
I can't set a title for each one of them, I can't add buttons, nothing.
I tried a few solutions to solve it that I found on the internet, but nothing worked.
I need control over the NavigationBar of each one of the views, as I need them to be different, with different title, etc.
This is my TabBar code:
class TabBar: UITabBarController {
let homeVC = HomeVC()
let followingVC = FollowingVC()
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBar.titleTextAttributes = [.foregroundColor: UIColor.appColors.mainWhite]
navigationController?.navigationBar.tintColor = UIColor.appColors.mainWhite
navigationItem.setHidesBackButton(true, animated: false)
homeVC.tabBarItem = UITabBarItem(tabBarSystemItem: .topRated, tag: 0)
followingVC.tabBarItem = UITabBarItem(tabBarSystemItem: .contacts, tag: 1)
let tabBarList = [homeVC, followingVC]
viewControllers = tabBarList
}
}
I really need the option to configure each NavigationBar from it's own ViewController, or atleast from the TabBar class.
You should add UINavigationController to each of your ViewControllers not your UITabBarController
First remove the UINavigationController of your TabBar, Either you have done this pragmatically or in the storyboard remove that first.
Second add UINavigationController to you ViewControllers
class TabBar: UITabBarController {
let homeVC = HomeVC()
let followingVC = FollowingVC()
override func viewDidLoad() {
super.viewDidLoad()
homeVC.tabBarItem = UITabBarItem(tabBarSystemItem: .topRated, tag: 0)
followingVC.tabBarItem = UITabBarItem(tabBarSystemItem: .contacts, tag: 1)
let homeNavigationController = UINavigationController(rootViewController: homeVC)
let followingNavigationController = UINavigationController(rootViewController: followingVC)
let tabBarList = [homeNavigationController, followingNavigationController]
viewControllers = tabBarList
}
}
Now if you change any properties like title and barButtons it will reflect accordingly.
Figured it out, the solution is:
The NavigationBar was not the TabBar navigation bar, but the screen that lead to the TabBar (Login Screen for example), I fixed it by hidding the navigation bar of the login screen when transfering to the TabBar controller, now the navigation bar of each view controller is shown and not blocked by the Login Viewcontrolelr navigationbar.

Present below current view and not above

I'm trying to present a view controller below another presented view controller (like WhatsApp when you open camera and press gallery).
I tried many things but none worked ..
Use child view controller and set view of that added child view controller at the top of hierarchy. It will be top most element, so actual background of this view will be obscured, but that's the way to go.
//code inside UIViewController class
func addViewControllerAtBottom() {
let newVC = NewVCType() //just instantiate it
addChildViewController(newVC)
view.insertSubview(newVC.view, at: 0) //at 0 means it's first rendered, all others will be on top of it
}
You can reproduce this behavior by doing the following :
First, create a NavigationController with a root ViewController :
let navController = UINavigationController(rootViewController: firstController)
Then, present this navigationController with animated: false and in the completion of the present method, push your second ViewController, still with animated: false (to avoid weird animations) :
present(navController, animated: false) {
navController.pushViewController(secondController, animated: false)
}
Here you go, you got a new navigation with 2 UIViewController, like WhatsApp.
Full code, wrapped into a button's action :
#IBAction func buttonTapped(_ sender: Any) {
let navController = UINavigationController(rootViewController: firstController)
present(navController, animated: false) {
navController.pushViewController(secondController, animated: false)
}
}

PresentModalViewController not showing navigation bar on next view

Hello I am using One tab bar button on toolbar , this button will show next view with table view ,Here is my code
[self presentModalViewController:self.navigationController
animated:YES];
my problem is that when I click this tab bar button it will showing next view with tableview but not navigation bar. because of this i am unable to perform delete operation in tableView.
How to solve the issue?
If you dont find the UINavigationBar on the next class means , it does not have a navigation controller, so before pushing it add a UINavigationController to your next view.
Try like this:
NextViewController *nextViewController=[[NextViewController alloc]initWithNibName:#"NextViewController" bundle:nil];
UINavigationController *navBar=[[UINavigationController alloc]initWithRootViewController:nextViewController];
[self.navigationController presentModalViewController:navBar animated:YES];
[navBar release];
[nextViewController release];
see this stackoverflow question for edit option.
You can simply add a button to navigation bar with ease
self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(editTable)] autorelease];
-(void)editTable{
[tableView setEditing: YES animated: YES];
}
All the best.
This code is called on button click event in classA VC:
ClassBVC* bVc = [[ClassBVC alloc] initWithNibName:#"ClassBVC" bundle:nil];
UINavigationController* tempNavCon = [[UINavigationController alloc] initWithRootViewController:bVc];
[self presentModalViewController:tempNavCon animated:YES];
[tempNavCon release];
[bVc release];
bVc = nil
;
and in class BVC in view did load you make an UIbarbutton item e.g:
UIBarButtonItem* barButton = [[UIBarButtonItem alloc] initWithTitle:#"Back" style:UIBarButtonItemStylePlain target:self action:#selector(backButtonClicked:)];
[barButton setTitle:#"Back"];
[self.navigationItem setLeftBarButtonItem:barButton];
[barButton release];
And in buttonClickedMethod simply dismiss the the model controller as:
-(void)backButtonClicked:(id)sender
{
[self dismissModalViewControllerAnimated:YES];
}
That is because you are using Modal to bring the new view controller.
Modally added/presented view controller will not be added to the navigation controller stack
if you are using navigationcontroller use like this
[self.navigationController pushViewController:nextController animated:YES];
Add navigation bar as sub view to the new view with bar button.
Try this
-(IBAction) editClick:(id)sender
{
[tableView setEditing:![tableView isEditing] animated:YES];
}
Swift 5
import UIKit
class ListVC: UIViewController {
// MARK: - Init
override func viewDidLoad() {
super.viewDidLoad()
//Background of the first screen
view.backgroundColor = .yellow
//Calling the instance of the navigation controller
let nav = self.navigationController?.navigationBar
//Defining the black theme on the navigation controller
nav?.barStyle = UIBarStyle.black
//Defining the white characters to make contrast with the black theme on the navigation controller
nav?.tintColor = UIColor.white
//Defining the custom color of the title font from navigation controller
nav?.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.orange]
//Defining the title of the navigation controller
nav?.topItem?.title = "List"
navigationItem.rightBarButtonItem = UIBarButtonItem.init(image: #imageLiteral(resourceName: "AddBtn"), style: .plain, target: self, action: #selector(hello))
// print(Realm.Configuration.defaultConfiguration.fileURL)
let realm = try! Realm()
print(Realm.Configuration.defaultConfiguration.fileURL)
}
// MARK: - Selector
/// A selector function that is called when the 'add' button is pressed on the navigation controller
#objc func hello() {
//Instance of the second screen
let addVC = AddVC()
//Add the navigationController to the new viewController
let navController = UINavigationController(rootViewController: addVC)
//Presenting the second screen modally
navigationController?.present(navController, animated: true, completion: nil)
}
}
//Other class
import UIKit
class AddVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//Background of the view
view.backgroundColor = .white
//Calling the instance of the navigation controller
let nav = self.navigationController?.navigationBar
//Initialize the title for the ViewController
nav?.topItem?.title = "Andrey"
// Initialize the right bar button item
navigationItem.rightBarButtonItem = setUpSaveButton()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.setNavigationBarHidden(false, animated: true)
}
/// Function that returns the "Save" bar button item
private func setUpSaveButton() -> UIBarButtonItem {
let button = UIBarButtonItem(title: "Save", style: .plain, target: self, action: #selector(saveAction))
button.setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.systemBlue],
for: .normal)
return button
}
#objc func saveAction() {
print("Saving..")
}
}
Swift 5.1
Presenting ViewController with navigation bar AND toolbar in fullscreen mode. If you don't put the row marked on comment the toolbar never show itself.
let sb = UIStoryboard(name: "retail_mainScreen", bundle: nil)
guard let mainVC = sb.instantiateViewController(withIdentifier: "mainScreen") as? retail_mainGest else { return }
let navController = UINavigationController(rootViewController: mainVC)
navController.isToolbarHidden = false //<--- remember this or toolbar will not appear
navController.modalPresentationStyle = .fullScreen
sender.vista.present(navController, animated: true, completion: nil)