JSQmessageView Controller: Add "Back" Button & Image on Navigation Bar, Swift - uinavigationbar

I'm using JSQmessageViewController and trying to programmatically add "back" button & user image on the navigation bar. I'm using the following codes. After running it, there's no "back" button or image. Attached is the screenshot of the simulator. I tested these codes with the normal UIViewController, and they worked.
May I know why they don't work with the JSQmessageViewController? And what should I do to add the "back" button & image on the navigation bar? Thanks a lot!
let navigationBar = UINavigationBar(frame: CGRectMake(0, 0, self.view.frame.size.width, 64))
navigationBar.backgroundColor = UIColor.whiteColor()
navigationBar.delegate = self;
let navigationItem = UINavigationItem()
navigationItem.title = strValue
let leftButton = UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.Plain, target: self, action: "back:")
self.navigationItem.leftBarButtonItem = leftButton
let imgButton = UIButton()
imgButton.setImage(image, forState: .Normal)
imgButton.addTarget(self, action: "EditProfile:", forControlEvents: UIControlEvents.TouchDown)
imgButton.frame = CGRectMake(self.view.frame.width - 60, 0, 41, self.view.frame.height)
var rightButton = UIBarButtonItem(customView: imgButton)
self.navigationItem.rightBarButtonItem = rightButton
navigationBar.items = [navigationItem]
self.view.addSubview(navigationBar)
}

So if you use a navigation controller to present your instantiation of the JSQMessagesViewController then the navigation bar should actually already be there. You can just provide it with those buttons and they will be in the correct place. It also seems that you may be doing things in an outdated syntax. Here is the latest Syntax.
Create a function to add your back button.
func addCancelButtonLeft() {
let button = UIBarButtonItem(barButtonSystemItem: .back, target: self, action: #selector(dismissView))
navigationItem.leftBarButtonItem = button
}
Create the action for the button.
func dismissView() {
dismiss(animated: true, completion: nil)
}
Then for your Image you are actually trying to put a button in that title view. Which is fine.
func titleView() {
let imgButton = UIButton()
imgButton.setImage(image, forState: .Normal)
imgButton.addTarget(self, action: #selector(EditProfile), forControlEvents: .touchUpInside)
navigationItem.titleView = imgButton
}
func EditProfile() {
navigationController?.present(EditProfileViewController(), animated: true, completion: nil)
}
let me know if you have more questions and I will see what I can do. Good luck 👍🏼

Related

navigationItem button not showing

I have a UINavigationItem i am trying to show a UIBarButtonItem.
Now the problem is i added them correctly, they're functional and working 100%.
but they're not showing on the UINavigationBar.
Now for the flow I am doing the following.
1- I am hiding the back button, like this
self.navigationItem.setHidesBackButton(isBackHidden, animated: false)
2- I am adding those 2 buttons using a function dynamically at run time, when a user tap on a UIButton.
let rightBarItem = UIBarButtonItem(title: "Button.Done".localized, style: .plain, target: self, action: #selector(self.saveButtonTapped))
navigationItem.rightBarButtonItem = rightBarItem
let leftBarItem = UIBarButtonItem(title: "Button.Cancel".localized, style: .plain, target: self, action: #selector(self.cancelButtonTapped))
navigationItem.rightBarButtonItem?.tintColor = .red // still nothing
navigationItem.leftBarButtonItem = leftBarItem
3- I have tried to use those functions and still the same result
self.navigationItem.setLeftBarButton(UIBarButtonItem?, animated: Bool)
self.navigationItem.setRightBarButton(UIBarButtonItem?, animated: Bool)
Summary :
I have tried to change the tintColor as they're functionally working i thought it was a color problem.
I have tried to use them inside DispatchQueue.main.async {} thinking it might be a thread problem since it dynamic.
I have debugged and check for the items in the UINavigationItem and they're exist.
What is going on mainly:
The buttons are not shown but they are working just fine when tapped on their places on the UINavigationItem.
Now the problem is i added them correctly, they're functional and
working 100%.
but they're not showing on the UINavigationBar.
Based on what you mentioned, it is just a UI issue -for unknown reason-.
So what you could do to confirm that there are button items will be shown in the navigation item is to let the bar button item to has a custom view. Adding a UIButton as a custom view for UIBarButtonItem would be valid, like this:
// right
let rightButton = UIButton(type: .custom)
rightButton.setTitle("Button.Done".localized, for: .normal)
rightButton.addTarget(self, action: #selector(saveButtonTapped), for: .touchUpInside)
let rightBarButtonItem = UIBarButtonItem(customView: rightButton)
navigationItem.setRightBarButton(rightBarButtonItem, animated: true)
// left
let leftButton = UIButton(type: .custom)
leftButton.setTitle("Button.Cancel".localized, for: .normal)
leftButton.addTarget(self, action: #selector(cancelButtonTapped), for: .touchUpInside)
let leftBarButtonItem = UIBarButtonItem(customView: leftButton)
navigationItem.setLeftBarButton(leftBarButtonItem, animated: true)
Therefore, for any needed UI update, you could edit rightButton and leftButton, example:
leftButton.layer.backgroundColor = UIColor.red.cgColor
leftButton.layer.borderWidth = 2.0
leftButton.layer.borderColor = UIColor.black.cgColor
In addition, I would assume that there is no need to call:
self.navigationItem.setHidesBackButton(isBackHidden, animated: false)
When setting the left bar button item, it should be a replacement for the back button by default.

Back UIBarButtonItem appearance remove text and change image

I've watched a lot of questions like this and didn't find an answer for my question.
That how i do now:
APPDELEGATE (didFinishLaunchingWithOptions)
// Text
let barButtonItem = UIBarButtonItem.appearance()
barButtonItem.setTitleTextAttributes([NSForegroundColorAttributeName: UIColor.clear], for: UIControlState.normal)
barButtonItem.setTitleTextAttributes([NSForegroundColorAttributeName: UIColor.clear], for: UIControlState.highlighted)
// Image
let backImage = UIImage(named: "arrow_left"
UINavigationBar.appearance().backIndicatorImage = backImage
UINavigationBar.appearance().backIndicatorTransitionMaskImage = backImage
And this almost fit to what i need, but the screen title shifted to the right as there is an invisible back button text. And it definetly is (the root controller's title has 9 characters length):
The question is: How to change image, hide text and keep standart back action for every appearance of back button in ios 9.0 ?
There are three ways to do what you want.
I recommend: Create your own Navigation Class by extending and UINavigationController and override backbuttonItem (UIBarButtonItem) property to customise it according to your requirement. And use the same Navigation Controller class in your project.
Create a custom backBarButton by extending UIBarButtonItem and manually set the same as a back button of default Navigation Controller class, in all view controller.
Hide default navigation bar from root controller and create your own navigation bar using UIView and UIButton in all view controllers. (I always use this choice, that makes customization of navigation bar very easy for me. And I can set my view according to my requirement)
Here is how you can add Custom button for your navigation bar
let btnleft : UIButton = UIButton(frame: CGRect(x:0, y:0, width:35, height:35))
btnleft.contentMode = .center
btnleft.setImage(Set_Local_Image("arrow_left"), for: .normal)
btnleft.addTarget(self, action: #selector(YOUR_ACTION), for: .touchDown)
let backBarButon: UIBarButtonItem = UIBarButtonItem(customView: btnleft)
self.navigationItem.setLeftBarButtonItems([menuBarButon], animated:false)
instead of "arrow_left" You can use any image you want
For Default back action you can create function(YOUR_ACTION) and use in selector of back button
navController.popViewController(animated: true)
I can suggest you 2 options. Both require BaseViewController class as a superclass of all your view controllers.
If you are ok with native back button image, just want to remove back button text you can use this subclass:
class BaseViewController: UIViewController {
var navigationTitle: String = ""
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if !navigationTitle.isEmpty {
navigationItem.title = navigationTitle
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
navigationTitle = navigationItem.title ?? ""
navigationItem.title = ""
}
}
If you want to use your custom icon for back button, you should create UIBarButtonItem with your image, add target, selector, handle action of the button. Sample BaseViewController class below:
class BaseViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let backImage = UIImage(named: "arrow_left")
navigationItem.hidesBackButton = true
guard let navigationController = navigationController else {
return
}
if navigationController.viewControllers.count > 1 {
// we have to set back button only when we have at least 1 controller to go back
navigationItem.leftBarButtonItem = UIBarButtonItem(image: backImage, style: .plain, target: self, action: #selector(backBarButtonAction(sender:)))
}
}
// MARK: Actions
func backBarButtonAction(sender: UIBarButtonItem) {
navigationController?.popViewController(animated: true)
}
}
According to https://stackoverflow.com/a/16831482/5790492 there is a way to do this without appearance.
Swift 3.0
extension UIViewController {
func setupCustomBackButton() {
if let controllersCount = navigationController?.viewControllers.count, controllersCount > 1 {
let backButton = UIButton(frame: CGRect(x: 0, y: 0, width: 12, height: 20))
backButton.setBackgroundImage(UIImage(named: "arrow_left"), for: .normal)
backButton.contentMode = .left
let backButtonItem = UIBarButtonItem(customView: backButton)
backButton.addTarget(self, action: #selector(self.popCurrentViewController), for: .touchUpInside)
navigationItem.leftBarButtonItem = backButtonItem
navigationItem.hidesBackButton = true
}
}
func popCurrentViewController() {
navigationController?.popViewController(animated: true)
}
}
UINavigationBar.appearance().setBackgroundImage(UIImage(), for:
UIBarPosition.any, barMetrics: UIBarMetrics.default)
UINavigationBar.appearance().shadowImage = UIImage()
UINavigationBar.appearance().tintColor = UIColor.white
UINavigationBar.appearance().barTintColor = UIColor.main
UINavigationBar.appearance().isTranslucent = false
UINavigationBar.appearance().clipsToBounds = false
UINavigationBar.appearance().backgroundColor = UIColor.main
UINavigationBar.appearance().titleTextAttributes = [NSFontAttributeName :
(UIFont(name: "Helvetica", size: 18))!, NSForegroundColorAttributeName:
UIColor.white]
Try this code and make changes accordingly to set image, color and other properties
You should watch Mark Moeykens' youtube series on this. He is IMHO one of the best YouTube presenters for UI Design and implementation in Swift.
The play list is https://www.youtube.com/playlist?list=PLHDMmeIMXj8WyvlX5uFmppVn2Pm0bXVr7
Create an extension for UINavigationItem
extension UINavigationItem {
func backBarButtonItem() -> UINavigationItem {
return UIBarButtonItem(title: "", style: .Plain, target: nil, action: nil)
}
}

Custom navigation bar button and action to open a new viewController

I´m trying to make a new custom navigation bar button with my own image. That´s working fine, but I´m trying to open a new view controller when I press that button. Unfortunately that doesn´t work and I have no idea how I should do it.
let testUIBarButtonItem = UIBarButtonItem(image: UIImage(named: "Image.png"), style: .plain, target: self, action: nil)
self.navigationItem.rightBarButtonItem = testUIBarButtonItem
func clickButton(sender: UIBarButtonItem){}
That´s my code right now and its inside my viewDidLoad. My intention is to perform a show detail Segue comment.
Can someone help me ?
why don't you just use a UIButton and assign it as bar button item as suggested in this thread:
UIBarButtonItem: target-action not working?
let button = UIButton(type: .Custom)
if let image = UIImage(named:"icon-menu.png") {
button.setImage(image, forState: .Normal)
}
button.frame = CGRectMake(0.0, 0.0, 30.0, 30.0)
button.addTarget(self, action: #selector(MyClass.myMethod), forControlEvents: .TouchUpInside)
let barButton = UIBarButtonItem(customView: button)
navigationItem.leftBarButtonItem = barButton
If you are using a Storyboard, add a manual segue to your ViewController and give it an identifier. Then you have to call performSegue in your custom navigationbar button's IBAction.
func clickButton(sender: UIBarButtonItem){
self.performSegue(withIdentifier: "yourSegueIdentifier", sender: nil)
}

How to display buttons on navigation bar in UIPageViewController?

I'm using a UIPageViewController connected to a UINavigationController to display two pages, a users table and a chat table.
I'm trying to implement the following:
Two buttons Users and Chat upon tapping which, the corresponding view controller appears. I want these buttons on the navigation bar.
Here's the code I've written in the page view controller class
viewDidLoad()
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let vc1 = storyBoard.instantiateViewControllerWithIdentifier("users")
let vc2 = storyBoard.instantiateViewControllerWithIdentifier("chat")
vcArray = [vc1, vc2]
self.setViewControllers([vc1], direction: .Forward, animated: true, completion: nil)
let button1 = UIButton(frame: CGRectMake(0, 30, self.view.frame.width/2, 30))
let button2 = UIButton(frame: CGRectMake(self.view.frame.width/2+1, 30, self.view.frame.width/2, 30))
button1.setTitle("Users", forState: .Normal)
button2.setTitle("Chat", forState: .Normal)
self.navigationController?.navigationBar.topItem?.titleView?.addSubview(button1)
self.navigationController?.navigationBar.topItem?.titleView?.addSubview(button2)
Unfortunately, none of the buttons appears in the navigation bar.
In fact, I can't even assign a title to the navigation bar. How can I fix this?
Thanks
You can add multiple button on the right side of navigation bar like this
let editImage = UIImage(named: "First")!
let searchImage = UIImage(named: "Second")!
let editButton = UIBarButtonItem(image: editImage, style: .Plain, target: self, action: "didTapEditButton:")
let searchButton = UIBarButtonItem(image: searchImage, style: .Plain, target: self, action: "didTapSearchButton:")
navigationItem.rightBarButtonItems = [editButton, searchButton]
or
self.navigationController?.navigationBar?.navigationItem.rightBarButtonItems = [editButton, searchButton]
If you want to make it look in the centre on the navigation bar, you
can use image with appropriate width so that it scales towards the center.

How to add button to NavBar while ViewController is embeded in as TabBarController

I try to add refresh button programmatically to my NavBar, while I am in TabBarController and I have a big problem with that. This is my code in ViewDidLoad():
let buttonItem = UIBarButtonItem(barButtonSystemItem: .Refresh, target: self, action: "refreshData")
self.navigationItem.rightBarButtonItem = buttonItem
any suggestions?
This is my storyboard after launch my app (no icon):
Make sure you viewController embed in UINavigationController first then add this navigation controller into tabViewController's view controllers array. After that use the method below:
let refresh = UIButton(frame: CGRectMake(0, 0, 40, 40))
//Set refresh image
refresh.setImage(UIImage(named: "refresh"), forState: UIControlState.Normal)
//or set text title
refresh.setTitle("Refresh", forState: .Normal)
refresh.addTarget(self, action: "refresh", forControlEvents: UIControlEvents.TouchUpInside)
self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: refresh)
EDIT:
what's your navBar? It's UINavigationBar, yes, it's possible:
let item = UINavigationItem(title: "")
item.rightBarButtonItem = UIBarButtonItem(title: "Refresh", style: UIBarButtonItemStyle.Done, target: self, action:"refresh")
item.hidesBackButton = true
UINavigationBar().pushNavigationItem(item, animated: false)
But normally it's should be embed in UINavigationController

Resources