center navigation bar views vertically - ios

I managed to increase the height of my navigation bar, but I faced with the problem, that title and buttons are situated in the bottom of navigator bar.
extension UINavigationBar {
open override func sizeThatFits(_ size: CGSize) -> CGSize {
let v = self.value(forKey: "frame") as? CGRect
return v?.size ?? CGSize(width: UIScreen.main.bounds.width, height: 44)
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationBar.frame = CGRect(x: 0, y: 0, width: bounds.width, height: 64)
}
I tried to set offset, using
navigationBar.setTitleVerticalPositionAdjustment(-10, for: .default)
navigationItem.leftBarButtonItem?.setBackgroundVerticalPositionAdjustment(-10, for: .default)
navigationItem.rightBarButtonItem?.setBackgroundVerticalPositionAdjustment(-10, for: .default)
navigationItem.rightBarButtonItem?.setBackButtonBackgroundVerticalPositionAdjustment(-10, for: .default)
navigationItem.leftBarButtonItem?.setBackButtonBackgroundVerticalPositionAdjustment(-10, for: .default)
Actually that setting only apply to my title, and the position of button bars remain the same.
But I don't think my solution is the best.

Its not a good practice to increase the size of the navigation bar. Instead you can add a uiview right under navigation bar with same color and remove the navigation bar border to make to look like height increased. Here is an example how yelp does it.

I posted the solution of this problem in another thread. Hope this helps.
vertically aligning UINavigationItems

Related

How to create custom navigation bar in swift?

I need to do a task that is about when I scroll my view to the top the navigation bar gets smaller and becomes like in the pictures below.
This is the code that I am using
self.navigationController?.navigationBar.setBackgroundImage(UIImage(named: "navBarImg"), for: UIBarPosition.any, barMetrics: .default)
//set navigation height
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let height = CGFloat(200)
navigationController?.navigationBar.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: height)
}
// when scroll
func scrollViewDidScroll(_ scrollView: UIScrollView) {
self.navigationController?.navigationBar.setBackgroundImage(UIImage(named: "back"), for: UIBarMetrics.default)
}
But nothing happens. Please can you tell me how to solve this problem? I know that in android there is solution and it's name is CoordinatorLayout, but in iOS I could not find any solution.

tabbar middle tab out of tabbar corner

I want to make a tab bar with 5 tab items. I want the middle one ( third ) to be out of tab bar's corner it may be tough to understand therefore I decided to add screenshot
I want to make something like you can see above but I don't know how it's possible.
I would appreciate any way you recommend to do it.
select tabbar Item and set its image insets
Make sure to get proper image (if using an image) goto Assets-> select desired image -> set property to always original
create a class of UITabBarController and assign it to the TabBarController.
initialise Variable
let button = UIButton.init(type: .custom)
Then in viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
button.setImage(UIImage(named: "IMAGE_NAME_FROM_ASSETS"), for: .normal)
button.backgroundColor = UIStyle.Color.CameraBG
button.layer.cornerRadius = 40
button.addShadow(offset: CGSize(width: 5, height: 5), color: UIStyle.Color.CameraShadow, radius: 5, opacity: 0.1)
button.addTarget(self, action: #selector(pressedAction(_:)), for: .touchUpInside)
self.view.insertSubview(button, aboveSubview: self.tabBar)
}
Add viewDidLayoutSubviews in your class
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// safe place to set the frame of button manually
button.frame = CGRect.init(x: self.tabBar.center.x - 40, y: self.view.bounds.height - 100, width: 80, height: 80)
}
Action You Want To Perform on button click
#objc func pressedAction(_ sender: UIButton) {
// do your stuff here
let nc = UINavigationController(rootViewController: YOURVC.storyboardInstance())
nc.modalPresentationStyle = .fullScreen
present(nc, animated: true, completion: nil)
}

Position Navigation Bar top of the safe area

I upgraded to a new iphone and upgrade my apps. I added in the x/xr/xs layout so the black borders are gone now.
I have a navigation bar at the top of my views but now it rides up into the status bar too much? How do I fix this? Doing it programmatically and not storyboard (to learn code).
Some code:
func buildTopbar()
{
statusbar = UIView(frame: CGRect(x: 0, y: 0, width: self.view.bounds.width, height: 20));
statusbar.backgroundColor = UIColor(red: 247/255, green: 247/255, blue: 247/255, alpha: 1.0);
navigationbar = UINavigationBar(frame: CGRect(x: 0, y: 20, width: self.view.bounds.width, height: 44));
navigationbar.barTintColor = UIColor(red: 247/255, green: 247/255, blue: 247/255, alpha: 1.0);
let texta = UIBarButtonItem(title: "A", style: .plain, target: self, action: #selector(settingToolbar(sender:)));
let textb = UIBarButtonItem(title: "B", style: .plain, target: self, action: #selector(inviteToolbar(sender:)));
texta.tintColor = ColorHelper.primaryColor();
textb.tintColor = ColorHelper.primaryColor();
...
navigationbar.setItems([title], animated: false);
self.view.addSubview(statusbar);
self.view.addSubview(navigationbar);
}
I set the status bar at 20 which was what it was in the old phones.
I'd recommend to create a UINavigationController and add your controller to that Navigation Controller, it will automatically adjust the navigation bar.
In case you want to manually add the navigation bar.
You must set it's frame Y position right.
To calculate starting Y position of Nav bar
let startingYPos = UIApplication.sharedApplication.statusBarFrame.size.height;
navigationbar = UINavigationBar(frame: CGRect(x: 0, y: startingYPos, width: self.view.bounds.width, height: 44));
My suggestion is go with adding some constraints for the top.And set the constraints values based on your iPhone device size or iOS Versions. Recently i achieved it by setting like this. My issues was with iOS Version, my view is near to status bar.So i set some constraints programatically and handled it. This way it wont affect the iphone screens below iphone 7.
In Viewdidload()
if #available(iOS 11, *) {
}
else{
topConstraints.constant = 20
}
Here i checked the version's. You can also check the device and you can set the constraints. If you want for the device check, let me know.
Hope it will work !!
Height of status bar has changed now from 20pt to 44pt (from iPhone X onwards). If you want to use your existing code, you need to apply device specific check for status bar height.
Here is a post which explains nav bar layout(for iPhone X and later devices) in more detail:
What is the top bar height of iPhone X?
I would suggest you to take UIScreen height & put it in a condition:
if UIScreen.main.bounds.size.height > 750 {
navigationBar = UINavigationBar(frame: CGRect(x: 0, y: 43, width: view.frame.size.width, height: 44))
}
else{
navigationBar = UINavigationBar(frame: CGRect(x: 0, y: 20, width: view.frame.size.width, height: 44))
}
it may not work if your view's having a scrolling view & it's height is set to more than default value, then try :-
view.bounds.size.height
You can have it aligned to the safe area even without UINavigationController or some "magic" fixed height constants.
You should have #IBOutlet of your navigation bar (or reference if navigation bar is made programmatically). Also, keep the bar's top constraint to Safe area.
Make your ViewController conform to UINavigationBarDelegate and set delegate of navigation bar (navigationBar.delegate = self)
Implement this function and return .topAttached:
func position(for bar: UIBarPositioning) -> UIBarPosition { return .topAttached }

Expanding UINavigationBar Height

I followed along here to get a bigger navigation bar working. The result is that it looks bigger, however not all elements of the bar actually expand, meaning that I can only interact with items places in the original size of the navigation bar. This is my pain point because I am trying to expand the UINavigationBar to put buttons in the expanded area and these can't be pressed.
Here's my code:
#IBDesignable
class CustomNavigationBar: UINavigationBar {
var customHeight: CGFloat = 88
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
let button = UIButton(frame: CGRect(x: 0, y: 44, width: 100, height: 44))
button.setTitle("Button", for: .normal)
button.backgroundColor = .red
button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
self.addSubview(button)
}
#objc func buttonAction() {
print("button pressed")
}
override func sizeThatFits(_ size: CGSize) -> CGSize {
return CGSize(width: UIScreen.main.bounds.width, height: customHeight)
}
override func layoutSubviews() {
super.layoutSubviews()
for subview in self.subviews {
var stringFromClass = NSStringFromClass(subview.classForCoder)
if stringFromClass.contains("UIBarBackground") {
subview.frame = CGRect(x: 0, y: 0, width: self.frame.width, height: customHeight)
subview.backgroundColor = .green
subview.sizeToFit()
}
stringFromClass = NSStringFromClass(subview.classForCoder)
if stringFromClass.contains("UINavigationBarContentView") {
subview.frame = CGRect(x: 0, y: 0, width: self.frame.width, height: customHeight)
subview.backgroundColor = .black
subview.sizeToFit()
}
}
}
}
Here's the screenshot from that output:
You can see here that when I resized the UIBarBackground in the layoutSubviews() function, I made it green and set it to the custom height, which worked. However when I resized the UINavigationBarContentView and set its colour to black, the colour gets set fine, but the height stays at 44.
See a screen shot of the debug view hierarchy below and we see that there are actually two items that still have the original height of 44.
All of this means that I cannot press the button in the view at all. However, if I move it up a bit so that it is inside the 44 height, then I can press it.
Looking for some help as to how I can properly resize all aspects of this nav bar
EDIT
If I remove the subview.sizeToFit() from the UInavigationBarContentView it resizes it to the correct size. I also noticed that the overridden sizeThatFits is never called?
i was try to change the height before but also i couldn't ,but
i makes the custom navigation controller and am call it on the viewDidLoad and hide the native navigation controller by doing
self.navigationController?.navigationBar.isHidden = true
and i display the custom in the same place and i put my views on this navigation controller also you can do animations on height this custom nav bar if you want
i hope this help you

How to create a custom navigation bar in Swift Xcode?

I am working on a chat app for my graduation project in iOS. I designed the following navigation bar:
Now I am trying to develop above graphic in my Xcode project, but I don't know if this is the correct way to achieve this and doesn't get it like the graphic.
I am using a xib file, that I load in my ViewController.swift using an instance of it. Than add it as the titleView of the navigationItem:
let helperView = HelperView()
navigationItem.titleView = helperView
This is the result of above code snippet:
The problem of this result is that it is overlapping the left bar button item and another problem, that I still doesn't figured out is, if the message bubble can have a dynamic height, when it have multiple lines (max is 3 lines).
Does anyone have experience with this kind of design within Xcode and is this the correct way to do this, or is there a better way to achieve this. Maybe a custom UINavigationController class?
Try create the whole navigation view that you desire, that mean the width is equal to the view, then try use this code to add it
navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
navigationController?.navigationBar.shadowImage = UIImage()
navigationController?.navigationBar.backgroundColor = .clear
navigationController?.view.insertSubview(subview, belowSubview: navigationController?.navigationBar)
It will makes your navigation bar become invisible but still showing the bar button
Update, by dimpiax
But better to override your UINavigationController class, and setup view in viewDidLoad
navigationBar.shadowImage = UIImage()
navigationBar.setBackgroundImage(UIImage(), for: .default)
navigationBar.backgroundColor = .clear
And on dependent viewController's view – show specific view.
// --------------------------------------------------------
// MARK:- Navigation SetUp
// --------------------------------------------------------
private func _navigationBarSetUp(){
///# Navigatoin bar and title #///
navigationController?.navigationBar.isHidden = false
navigationItem.title = vEditScreenName
navigationController?.navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor : ColorTheme.white, NSAttributedString.Key.font: UIFont(descriptor: UIFontDescriptor(name: "Poppins-Regular", size: 20), size: 20)]
self.view.backgroundColor = ColorTheme.vidBoomBrandPurple
///# Navigation bar back button #///
let btnBack = UIButton(frame: CGRect(x: 0, y: 0, width: 25, height: 25))
btnBack.setImage(UIImage(named: "icon_back_arrow"), for: .normal)
btnBack.addTarget(self, action: #selector(_handlebtnBackTapped), for: .touchUpInside)
navigationItem.leftBarButtonItem = UIBarButtonItem(customView: btnBack)
///# Navigation bar explore button #///
let btnExport = UIButton(frame: CGRect(x: 0, y: 0, width: 80, height: 25))
btnExport.setTitle("Export", for: .normal)
btnExport.backgroundColor = .orange
btnExport.layer.cornerRadius = 18
btnExport.addTarget(self, action: #selector(_handleBtnExportTapped), for: .touchUpInside)
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: btnExport)
}
// --------------------------------------------------------
// MARK:- UIBarButtonItem Action
// --------------------------------------------------------
#objc fileprivate func _handlebtnBackTapped() {
self.player.stop()
navigationController?.popViewController(animated: true)
navigationController?.navigationBar.isHidden = true
}
#objc func _handleBtnExportTapped(){
self.player.stop()
let svc = ShareVideoVC(nibName: "ShareVideoVC", bundle: nil)
svc.videoString = videoString
saveFile()
self.navigationController?.pushViewController(svc, animated: true)
}

Resources