I know there are a lot of questions out there on this topic; however, none of those answers have helped me and I have tried so many ways of going about solving this. My problem is that my bar button will not show up, originaly, but when the viewcontroller is presented later on in the app it will show up then but the navigation title won't show up. I'm not sure why that is, but I believe it has something to do with the SwipeNavigationController framework that I'm using. My goal is to have the button show up as it's supposed to when the user swipes left to get to that view, and also when the view is later called and presented to look the same. The code for adding the navItem is below:
let cameraBarButton = UIBarButtonItem(image: #imageLiteral(resourceName: "cameraIcon"), style: .plain, target: self, action: #selector(goToCamera))
navigationItem.rightBarButtonItem = cameraBarButton
Please look at this other post to get a little better understanding of the framework. As well as here is the code on how I set up the navigation bar:
override func viewDidLoad() {
super.viewDidLoad()
setupView()
let barHeight: CGFloat = UIApplication.shared.statusBarFrame.size.height
let displayWidth: CGFloat = self.view.frame.width
let displayHeight: CGFloat = self.view.frame.height
messagesTableView = UITableView(frame: CGRect(x: 0, y: barHeight, width: displayWidth, height: displayHeight - barHeight))
messagesTableView.register(BlankCell.self, forCellReuseIdentifier: blankCellID)
messagesTableView.dataSource = self
messagesTableView.delegate = self
self.view.addSubview(messagesTableView)
view.backgroundColor = UIColor.white
setupNavButtons()
setupNavBar()
showNoMessagesLabel()
navigationController?.isNavigationBarHidden = false
if #available(iOS 11.0, *) {
navigationController?.navigationBar.prefersLargeTitles = true
self.navigationController?.navigationBar.largeTitleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.white]
} else {
// Fallback on earlier versions
}
}
override func viewWillAppear(_ animated: Bool) {
if #available(iOS 11.0, *) {
navigationController?.navigationBar.prefersLargeTitles = true
self.navigationController?.navigationBar.largeTitleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.white]
setupNavBar()
} else {
setupNavBar()
}
}
func setupNavBar() {
UIApplication.shared.statusBarStyle = .lightContent
self.navigationController?.isNavigationBarHidden = false
self.navigationController?.navigationBar.topItem?.title = "Messages"
self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.white]
self.navigationController?.navigationBar.barTintColor = UIColor.pinkNeonColor
self.navigationController?.navigationBar.tintColor = UIColor.white
}
func setupNavButtons() {
let cameraButton = UIButton(type: .system)
cameraButton.setImage(#imageLiteral(resourceName: "cameraIcon").withRenderingMode(.alwaysOriginal), for: .normal)
cameraButton.frame = CGRect(x: 0, y: 0, width: 34, height: 34)
navigationItem.leftBarButtonItem = UIBarButtonItem(customView: cameraButton)
}
Related
Screenshot of the gap
I need to present a popover view from a UIBarbuttonItem in a UIToolbar. But there exists a gap between the popover view and the toolbar.
private func addToolbar() {
let toolBar = UIToolbar(frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: 50))
let item1 = UIBarButtonItem(image: UIImage(systemName: "pencil"), style: .plain, target: self, action: #selector(item1Pressed(_:)))
let item2 = UIBarButtonItem(image: UIImage(systemName: "house"), style: .plain, target: self, action: #selector(item2Pressed(_:)))
toolBar.sizeToFit()
toolBar.items = [item1, item2]
textField.inputAccessoryView = toolBar
}
class SearchViewController: UIViewController {
let searchBar = UISearchBar()
weak var viewControllerDelegate: SearchViewControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
setupView()
setupSearchbar()
}
private func setupView() {
view.backgroundColor = .white
navigationController?.navigationBar.prefersLargeTitles = true
self.title = "Search"
}
private func setupSearchbar() {
searchBar.sizeToFit()
searchBar.placeholder = "Search test"
searchBar.showsCancelButton = true
searchBar.delegate = self
self.navigationItem.titleView = searchBar
}
}
I tried setting the sourceRect of the presented popover view, but the popover view doesn't move down below a certain point.
#objc private func item1Pressed(_ sender: UIBarButtonItem) {
let vc = SearchViewController()
vc.viewControllerDelegate = self
let navVC = UINavigationController(rootViewController: vc)
navVC.modalPresentationStyle = .popover
navVC.popoverPresentationController?.delegate = self
navVC.popoverPresentationController?.permittedArrowDirections = .any
navVC.preferredContentSize = CGSize(width: 500, height: 200)
navVC.popoverPresentationController?.sourceItem = sender
var location = CGPoint(x: 0, y: 0)
if let barItemView = sender.value(forKey: "view") as? UIView {
let barFrame = barItemView.frame
let rect = barItemView.convert(barFrame, to: view)
location = rect.origin
}
navVC.popoverPresentationController?.sourceRect = CGRect(x: location.x, y: location.y+100, width: 0, height: 0)
present(navVC, animated: true)
}
I want to apply UINavigation custom background image and back button image also for iOS 14 everything is working fine but as I try to run the app on iOS 15 back button image not working instead it's showing the default back button which I want to replace with custom back button image I am using below code
if #available(iOS 15.0, *) {
let appearance = UINavigationBarAppearance()
appearance.configureWithTransparentBackground()
appearance.backgroundImage = image
appearance.setBackIndicatorImage(backButtonImage, transitionMaskImage: backButtonImage)
if Locale.current.languageCode == "fr" {
appearance.titleTextAttributes = [ NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 14), NSAttributedString.Key.foregroundColor: UIColor(hexString: "#231F20")]
} else {
appearance.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor(hexString: "#231F20")]
}
navigationItem.standardAppearance = appearance
navigationItem.scrollEdgeAppearance = appearance
} else {
self.navigationController?.navigationBar.setBackgroundImage(image, for: .default)
self.navigationController?.navigationBar.backIndicatorImage = backButtonImage
self.navigationController?.navigationBar.backIndicatorTransitionMaskImage = backButtonImage
if Locale.current.languageCode == "fr" {
self.navigationController?.navigationBar.titleTextAttributes = [ NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 14), NSAttributedString.Key.foregroundColor: UIColor(hexString: "#231F20")]
} else {
self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor(hexString: "#231F20")]
}
}
Sharing with you a common function I have made in a BaseViewController which is the superclass of all my View Controllers.
I Simply call the addBackButton function from viewDidLoad from any of the VC I want to add the back button.
It also handles the back navigation automatically. (takes care if you have presented or pushed a vc)
func addBackButton(tint : UIColor? = nil, backImage : UIImage? = Constants.Images.kImageForBackNavigation){
let buttonForBack = UIButton(type: .custom)
var tintColorForImage = UIColor.white
if tint != nil {
tintColorForImage = tint!
}
let image = backImage!.withRenderingMode(.alwaysTemplate)
buttonForBack.setImage(image, for: .normal)
buttonForBack.imageView?.tintColor = tintColorForImage
buttonForBack.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
buttonForBack.addTarget(self, action: #selector(BaseViewController.closeViewController), for: .touchUpInside)
let barButtonItemForClose = UIBarButtonItem(customView: buttonForBack)
self.navigationItem.setLeftBarButton(barButtonItemForClose, animated: false)
}
#objc func closeViewController(){
if self == self.navigationController?.children.first {
DispatchQueue.main.async {
self.navigationController?.dismiss(animated: true, completion: nil);
}
}
else{
DispatchQueue.main.async {
self.navigationController?.popViewController(animated: true)
}
}
}
I am trying to get a back button on my MyServiceTypeSelector() controller so that after i present MyServiceTypeSelector() I can go back to the BRPServiceSelector() controller , how can i do this ? do i some how need to embed it with a nav controller and if so i am not using storyboards so it would need to be done programmatically?
import Foundation
import UIKit
class BRPServiceSelector: UIViewController, UITextFieldDelegate {
override func viewDidLoad() {
super.viewDidLoad()
setupViews()
}
let businessAccountLabel: UILabel = {
let label = UILabel()
label.text = "Business Account"
label.backgroundColor = .white
label.translatesAutoresizingMaskIntoConstraints = false
label.textAlignment = .center
return label
}()
lazy var serviceSelectorButton: UIButton = {
let button = UIButton(type: .system)
button.backgroundColor = UIColor.black
button.setTitle("Select A Service Type?", for: .normal)
button.setTitleColor(UIColor.white, for: .normal)
button.addTarget(self, action: #selector(presentServiceSelector), for: .touchUpInside)
button.layer.cornerRadius = 3
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 14)
return button
}()
func presentServiceSelector(){
let msts = MyServiceTypeSelector()
let navController = UINavigationController(rootViewController: msts)
self.present(navController, animated: true, completion: nil)
let containerView: UIView = {
let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = .white
return v
}()
let scrollView: UIScrollView = {
let v = UIScrollView()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = .white
return v
}()
func setupViews(){
containerView.addSubview(serviceSelectorButton)
serviceSelectorButton.anchor(top: containerView.topAnchor, left: nil, bottom: nil, right: nil, paddingTop: 50, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 220, height: 25)
serviceSelectorButton.centerXAnchor.constraint(equalTo: containerView.centerXAnchor).isActive = true
}
}
}
If you want the VC in the navigation stack then push it onto the stack instead of presenting it. presenting is normally used for modal windows and they dont usually have navigation bars.
self.navigationController?.pushViewController(vc, animated: true)
I'm trying trying to change my toolbar that I added Programmatically. but it didn't reflect. so any help
this is my code. and in the viewController I embed the view from UINavigation Controller
class ViewController: UIViewController,UIToolbarDelegate {
private var toolItems : [UIBarButtonItem] = []
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
navigationController?.isToolbarHidden = false
let height: CGFloat = 130
let bounds = self.navigationController?.toolbar.bounds
navigationController?.toolbar.barTintColor = UIColor(red: 0.0/42, green: 0.0/42, blue: 0.0/56, alpha: 1)
navigationController?.toolbar.tintColor = UIColor.white
navigationController?.toolbar.frame = CGRect(x: 0, y: self.view.frame.height - 80, width: self.view.frame.width, height: (bounds?.height)! + height)
navigationController?.toolbar.isTranslucent = false
navigationController?.toolbar.heightAnchor.constraint(equalToConstant: (bounds?.height)! + height).isActive = true
navigationController?.toolbar.sizeToFit()
let btn_Tracking = UIButton(type: .custom)
btn_Tracking.setImage(UIImage(named: "icon-trackingtabbed#2x"), for: .normal)
btn_Tracking.sizeToFit()
let trackingItem = UIBarButtonItem(customView: btn_Tracking)
///Sign
let btn_sign = UIButton(type: .custom)
btn_sign.setImage(UIImage(named: "icon-trackingtabbed#2x"), for: .normal)
btn_sign.sizeToFit()
let sginItem = UIBarButtonItem(customView: btn_sign)
let fixedSpace: UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.fixedSpace, target: nil, action: nil)
fixedSpace.width = 10.0
let flexibleSpace: UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil)
self.toolbarItems = [flexibleSpace,sginItem,flexibleSpace,trackingItem,flexibleSpace]
}
}
When my project was in Swift 2, I had this code that worked:
extension UINavigationController {
func hairLine(hide: Bool) {
//hides hairline at the bottom of the navigationbar
for subview in self.navigationBar.subviews {
if subview.isKind(of: UIImageView.self) {
for hairline in subview.subviews {
if hairline.isKind(of: UIImageView.self) && hairline.bounds.height <= 1.0 {
hairline.isHidden = hide
}
}
}
}
}
}
But now something changed and it doesn't work. Not sure if it because of Swift 3, or iOS10, or that I'm now testing with a 7plus vs a 6s, but it no longer works. I would call in it viewWillAppear of the view controller that is being shown. I saw an answer on here saying to use
UINavigationBar.appearance().shadowImage = UIImage()
UINavigationBar.appearance().setBackgroundImage(UIImage(), for: .default)
but that hasn't worked. I tried replacing the content of my old hairLine() with those 2 lines, tried putting them directly in viewWillAppear and viewDidAppear but still doesn't work for me.
Try this
self.navigationController?.navigationBar.setValue(true, forKey: "hidesShadow")
Before:
After:
Code:
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Hello World"
let navbarColor = UIColor(colorLiteralRed: (247/255), green: (247/255), blue: (247/255), alpha: 1)
let image = UIImage()
navigationController?.navigationBar.setBackgroundImage(image, for: .default)
navigationController?.navigationBar.shadowImage = image
navigationController?.navigationBar.backgroundColor = navbarColor
let statusBarHeight = UIApplication.shared.statusBarFrame.height
let statusBarWidth = UIScreen.main.bounds.size.width
let statusBarView = UIView(frame: CGRect(x: 0, y: 0, width: statusBarWidth, height: statusBarHeight))
statusBarView.backgroundColor = navbarColor
view.addSubview(statusBarView)
}
Try:
self.navigationController?.navigationBar.setBackgroundImage(_:UIImage(),
for: .any,
barMetrics: .default)
self.navigationController?.navigationBar.shadowImage = UIImage()
in viewDidLoad()
Try this
UINavigationBar.appearance().setBackgroundImage(_:
nil,
for: .any,
barMetrics: .default)
UINavigationBar.appearance().shadowImage = nil