I am using right Slider menu in my application in which i have set NavigationController height but if we are navigating through slider menu options then the view show the default height of slider navigation controller.
Navigation Bar Height:
self.navigationController?.navigationBar.frame = CGRect(x:0, y:0, width:self.view.frame.size.width, height:80)
In slider menu, we are navigating like this:
let mainViewController = storyboard.instantiateViewController(withIdentifier: "MainViewController") as! MainViewController
self.loginViewController = UINavigationController(rootViewController: mainViewController)
self.slideMenuController()?.changeMainViewController(self.allPhotosViewController, close: true)
As per my understanding you can't did customization in Default NavigationBar frame but yes it is possible with CustomNavigationBar.
Create CustomNavigationBar extend from UIView & make design as per need .
Here is the code for what #Mukesh has shown:
import UIKit
class CustomNavigationBar: UINavigationBar
{
override func draw(_ rect: CGRect)
{
// Drawing code
self.frame.size.height = 90
self.backgroundColor = UIColor.red
}
}
You don't need a Xib file. You can just create a Swift file and then in you Storyboard file edit the NavigationBar Custom Class : Class which is what #Mukesh has done in his screen shot. I have tested it and it works.
Related
I'm trying to add a UIView beneath the UINavigationBar in my UINavigationController.
The view will serve as a placeholder for information messages (for example if we are having issues and content is not getting updated).
Adding the view it self and setting it's constraints is not an issue, but it is overlapping the content of the views that is contained in the navigation controller, which is not want I want. How can I set the content of the contained viewcontroller to respect the space which this new view takes up?
The screenshot is showing my custom (orange) view overlapping the content of the viewController that was pushed on to the navigation controller.
Try Subclassing the UINavigationController and then add your orange view's height constraint to it. and call the function whenever you need it
import UIKit
class CustomNavigationController: UINavigationController{
#IBOutlet weak var topViewHeight: NSLayoutConstraint!
func animateHeight(height: CGFloat){
UIView.animate(withDuration: 0.2) {
self.viewControllers.forEach{ vc in
let v = vc.view.frame
vc.view?.frame = CGRect(x: 0, y: height, width: v.width, height: v.height)
}
self.topViewHeight.constant = height
}
}
}
how to use it?
in your VC where you want to show/hide it:
(self.navigationController as? CustomNavigationController)?.animateHeight(height: 50)
I have an app with a tabbar and a navbar.
I have a BaseVC and a DetailVC. I'm pushing DetailVC from BaseVC. I want the tabbar to be under the pushed VC DetailVC. I'm using hidesBottomBarWhenPushed to achieve it. It works great, but for some reason while it's animating the push the tabbar is still visible and just when the animation ends the tabbar is hidden. I want it to be under the pushed VC in the animation too.
My code is:
self.hidesBottomBarWhenPushed = true
self.navigationController?.pushViewController(detailVC, animated: true)
self.hidesBottomBarWhenPushed = false
And the result (the bug) is this:
Anyone has an idea why the tabbar "jumps"? Thank you!
Having looked at the project in question I have found one way to make it work:
Remove the viewWillLayoutSubviews from the TabBarViewController so that it is not determining the height of the tab bar anymore and thus not stopping the animation working correctly.
Create a new swift file called MyTabBar (or whatever you want) and put this in it:
import UIKit
class MyTabBar: UITabBar {
var tabBarHeight: CGFloat = 100
override func sizeThatFits(_ size: CGSize) -> CGSize {
let superSize = super.sizeThatFits(size)
return CGSize(width: superSize.width, height: self.tabBarHeight)
}
}
Create a storyboard called TabBarStoryboard (or whatever). It's not going to be used for anything other then to hold a UITabBarController which you later create.
In the storyboard set the class type of the UITabBarController to your class of TabBarViewController so it gets the correct class when instantiated.
In the storyboard set the class type of the UITabBar that belongs to the UITabBarController to MyTabBar so that it too is the correct class when instantiated.
In your RootViewController replace this:
fileprivate let tabBarViewController = TabBarViewController()
with this:
fileprivate lazy var tabBarViewController: TabBarViewController = {
let storyboard = UIStoryboard(name: "TabBarStoryboard", bundle: nil)
return storyboard.instantiateViewController(withIdentifier: "MyTabBarController") as! TabBarViewController
}()
In your TabBarViewController add this to the end of the viewDidLoad to set the height of the tab bar:
if let tabBar = self.tabBar as? MyTabBar {
tabBar.tabBarHeight = self.tabBarHeight
}
Now if you get all that correct you should have a tab bar the size you want and the animation should work correctly because the height of tab bar is not longer controlled by the viewDidLayoutSubviews method.
I had to use a storyboard to hold the basic UITabBarController because I couldn't find a way to set the class of its UITabBar property otherwise (if anyone knows a way add a comment.
In case this is difficult to follow I have uploaded my version of your project to dropbox and this is the link: PlayWiz-NewVersion.zip. Be careful as it will unzip to the same directory structure so extract it to a different folder than the original otherwise you will lose the original.
That method appears to work correctly for me and I see no reason for there to be any problem but test it thoroughly first.
I have a simpler variation of the above example (cheers by the way)
I pasted everything in viewDidLoad, but you can write it prettier.
class TabBarController: UITabBarController {
override func viewDidLoad() {
// create the normal buttons (controllers)
let viewControllers = [UINavigationController(rootViewController: firstButton), UINavigationController(rootViewController: secontButton)]
self.viewControllers = viewControllers
// create the middle rounded button
self.tabBar.addSubview(addItemButton)
// setup constraints
addItemButton.widthAnchor.constraint(equalToConstant: 64).isActive = true
addItemButton.heightAnchor.constraint(equalToConstant: 64).isActive = true
tabBar.centerXAnchor.constraint(equalTo: self.addItemButton.centerXAnchor).isActive = true
tabBar.topAnchor.constraint(equalTo: self.addItemButton.centerYAnchor, constant: -8).isActive = true
}
extension UITabBar {
// fix clicking the (+) external to the tabbar bounds
override open func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
if (!self.clipsToBounds && !self.isHidden && self.alpha > 0.0) {
let subviews = self.subviews.reversed()
for member in subviews {
let subPoint = member.convert(point, from: self)
if let result:UIView = member.hitTest(subPoint, with:event) {
return result;
}
}
}
return super.hitTest(point, with: event)
}
// this fixes the "jumping" tabBar when using the "hidesBottomBarWhenPushed = true"
override open func sizeThatFits(_ size: CGSize) -> CGSize {
let superSize = super.sizeThatFits(size)
return CGSize(width: superSize.width, height: 85)
}
}
Now, just call hidesBottomBarWhenPushed = true and push the desired view controller.
I have a basic navigation setup in my Storyboard: a vanilla UIViewController embedded in a UINavigationController. In my main VC I have two buttons that each segue to a UIViewController subclass: LabelledVC. In the subclass's viewDidAppear(_:) method I set the navigation item's titleView to a custom image:
class LabelledVC: UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let logoImage = UIImage(named: "apple")
let logo = UIImageView(image: logoImage)
logo.contentMode = .scaleAspectFit
logo.frame = CGRect(x: 0, y: 0, width: 32, height: 32)
navigationItem.titleView = logo
}
}
For some reason LabelledVC's viewDidAppear(_:) method is being called when the app loads (before it is pushed onto the navigation stack) which doesn't make any sense to me. You can find the project here.
Your MainVC is inherit from LabelledVC. So when application did show this controller the system calling viewDidAppear in ViewController but you don't have implementation for this method, so system call this method from parent class.
One other thing. For your example best place to configure NavigationItem is viewDidLoad method.
I'm using this Framework to have a moving UINavigationBar. I have the following problem with every View (since every view has a UITableView or UICollectionView - Yes this bug appears with UICollectionView, too)
The bottom of every Screen is missing in the size of the UINavigationBar.
The controller is a subclass of UIViewController.
open class SLPagingViewSwift: UIViewController, UIScrollViewDelegate
The UIViewControllers are created globally:
var settingsVC: UserSettingsVC?
Instantiated within the class that creates the controller:
appDelegate.window = UIWindow(frame: UIScreen.main.bounds)
settings = settingsStb.instantiateViewController(withIdentifier: "UserSettingsVC") as? UserSettingsV
// among other VCs
self.setItems() //sets the images at the navigationbar
let items = [itemsArray]
let controllers = [arrayOfVCs] as [UIViewController]
controller = SLPagingViewSwift(items: items, controllers: controllers, showPageControl: false)
controller.indexSelected = 1
nav = UINavigationController(rootViewController: controller)
appDelegate.window?.rootViewController = nav
appDelegate.window?.backgroundColor = cachedBlack
appDelegate.window?.makeKeyAndVisible()
The example controller is a UITableViewController. Same bug appears in every other UIViewController with a UITableView as well as in one UITableViewController with a UICollectionView.
What am I missing? Help is very appreciated.
What you need to do is create a global constant and set the UIEdgeInsetsMake(), for example:
let collectionViewInset = UIEdgeInsetsMake(0, 0, 44, 0)
44 is the height of the navigation bar, and you need to start it after the navigationBar, so y = 44.0.
After doing that you need to set:
collectionView.contentInset = collectionViewInset
And that's it, sorted!
I am having troubles setting the self.navigationItem.titleView, could someone please help me catch my mistake.
import Foundation
class CustomNavigationController: UINavigationController
{
override func viewDidLoad() {
let logo = UIImage(named: "browse_back")
var hexColor = 0x21BBD4 as UInt
self.navigationBar.barTintColor = GeneralHelper.UIColorFromRGB(hexColor)
self.navigationItem.titleView = UIImageView(image: logo)
}
}
Here is my code for setting the titleView to an image.
When I run the application, the color of the navigation bar is being changed to the correct color, but the titleView image is not displaying.
I've tested to ensure the image does exist.
Thanks.
The managing UINavigationController object uses the navigation items
of the topmost two view controllers to populate the navigation bar
with content.
Source: UINavigationItem Class Reference
You have to set the titleView of the navigationItem of the controller that is the top most controller in the navigation stack managed by your custom navigation controller.
For those using a UILabel as your titleView
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
navigationItem.titleView?.sizeToFit()
}
Hope this works!