Trying to make rightBarButton appear after making it disappear using Swift - ios

I currently am working on an app in Swift where in my viewDidLoad() method I have purposely hidden my rightBarButton on my navigation bar like this:
self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Done, target: self, action: #selector(TableViewController.dismiss))
self.navigationItem.setRightBarButtonItem(nil, animated: true)
However, under certain circumstances, I would like to display the rightBarButton. How would I do this? What would be the opposite of the above line of code?

Once you set the bar button item to nil, it is gone. Something you can do however, is store the bar button item like so:
let barButtonItem = UIBarButtonItem(barButtonSystemItem: .Done, target: self, action: #selector(TableViewController.dismiss));
and then you can make it appear/disappear like so:
self.navigationItem.rightBarButtonItem = barButtonItem
self.navigationItem.setRightBarButtonItem(nil, animated: true)
then just access the barButtonItem whenever you want it to appear/disappear.

You can do one of the following two options:
Keep a reference of your UIBarButtonItem and every time you disappear you save it to then when you want to show it again you set the old value.
Play with the color of the UIBarButtonItem and the enabled/disable property to enable the interaction with it.
The first choice always keep a reference globally to the UIBarButtonItem and the second need to know the exact color of the original UIBarButtonItem to give to its original state:
First Option:
private var isHidden: Bool!
private var righBarButtonItem: UIBarButtonItem!
#IBAction func hideButton(sender: AnyObject) {
if self.isHidden == true {
self.isHidden = false
self.navigationItem.rightBarButtonItem = righBarButtonItem
}
else {
self.isHidden = true
righBarButtonItem = self.navigationItem.rightBarButtonItem
self.navigationItem.setRightBarButtonItem(nil, animated: true)
}
}
Second Option:
#IBAction func hideButton(sender: AnyObject) {
if self.isHidden == true {
self.isHidden = false
self.navigationItem.rightBarButtonItem?.tintColor = UIColor.clearColor()
self.navigationItem.rightBarButtonItem?.enabled = false
}
else {
self.isHidden = true
self.navigationItem.rightBarButtonItem?.tintColor = UIColor.blueColor()
self.navigationItem.rightBarButtonItem?.enabled = true
}
}
In the above examples I set a variable with the state of the UIBarButtonItem for purposes of know the value and and #IBOutlet to hide/show the UIBarButtonItem. The variable isHidden need to set it's initial value in the viewDidLoad.
I hope this help you.

Related

How to apply custom UIimage to editButtonItem in Swift?

I'm not sure how to apply custom UIImage to editButtonItem.
In my view controller, I configured the bar button item as editButton.
func configureNavigationBar() {
navigationItem.largeTitleDisplayMode = .always
navigationController?.navigationBar.prefersLargeTitles = true
navigationController?.navigationBar.sizeToFit()
navigationItem.title = "TEST"
navigationItem.rightBarButtonItem = editButtonItem
extendedLayoutIncludesOpaqueBars = true
}
It gives me a default edit/done edit button, but now I have UIImage for the edit button and want to display them instead of the default edit/done button.
I also have setEditing function in my view controller to set my collection view cells to the edit mode.
override func setEditing(_ editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
if (editing){
collectionView.isEditing = true
} else {
collectionView.isEditing = false
}
}
It works perfectly until I add a custom UIimage to the editButtonItem.
I tried adding My custom UIimage using the following code.
navigationItem.rightBarButtonItem = UIBarButtonItem(image: Images.edit, style: .plain, target: self, action: #selector(setEditing(_:animated:)))
But when I implement the code above, I cannot trigger the setEditing function; it didn't go in the editing mode and stuck with not-editing mode forever.
I also tried keeping the following line
navigationItem.rightBarButtonItem = editButtonItem
and tried overriding the editButtonItem to something like,
override var editButtonItem: UIBarButtonItem {
get {
var result = UIBarButtonItem()
if isEditing {
print("isEdit true")
result = UIBarButtonItem(customView: UIImageView(image: Images.edit))
} else {
print("isEditfalse")
result = UIBarButtonItem(customView: UIImageView(image: Images.editDone))
}
return result
}
}
but it also makes the view stuck in the non-editing mode and cannot enter the editing mode. (as for the overriding editButtonItem, I guess I'm doing something wrong(?))
Could anyone point me out how to use the custom UIImage for the editButtonItem?
Thanks to #lazarevzubov, I used setRightBarButton() and add the following code and now it works.
override func setEditing(_ editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
rightBarButtonImage = collectionView.isEditing ? Images.edit.withRenderingMode(.alwaysOriginal) : Images.editDone.withRenderingMode(.alwaysOriginal)
navigationItem.rightBarButtonItem?.image = rightBarButtonImage
collectionView.isEditing = !collectionView.isEditing
}

UIBarButtonItem position different when placed via storyboard vs. programmatically

In my app, I have a toolbar with UIBarButtonItems.
In most circumstances, the UIBarButtonItems are set via storyboard, and look as follows:
In a special case, I have to replace one UIBarButtonItem programmatically. This is done with the following code:
let rotatingButton = UIButton(type: .custom)
rotatingButton.setImage(UIImage(named: "LocalizationInUseNoFix"), for: .normal)
rotatingButton.addTarget(self, action: #selector(localizationButtonTapped), for: .touchUpInside)
rotatingButton.rotateStart()
let barButtonItem = UIBarButtonItem(customView: rotatingButton)
leftBarButtonItems![2] = barButtonItem
When the rotatingButton is displayed in the toolbar, it placed at a different position. It is shifted to the right, as you can see here:
How can I achieve to place both UIBarButtonItems at the same position?
EDIT:
By now I realized that the horizontal shift of the programmatically created UIBarButtonItem is not always the same, without any changes to the code: Sometimes it is shifted left, and not right:
EDIT 2:
I found a workaround:
If I set a width constrain to my button like
rotatingButton.widthAnchor.constraint(equalToConstant: 40).isActive = true
then the button is apparently always correctly placed. But I hate to hard-code constraints like this.
Is there a more elegant way to do it?
Try the below steps to perform your task:
Store left bar button items into an NSMutableArray
Replace desired UIBarbuttonItem
Set leftbarbuttonitems to this new array
Hope this steps will work
When you set the image on UIBarButton programmatically, the contentmode of the leftBarButtonItems becomes 'left' and rightBarButtonItems become 'right'. But from storyboard, it is centered. Set the image and adjust the contentMode as required.
All are working fine for Navigationbar and Toolbar
class ViewController: UIViewController {
#IBOutlet weak var toolbar: UIToolbar!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func leftAction(_ sender: Any) {
}
#IBAction func rightAction(_ sender: Any) {
}
#IBAction func changeLeftItems(_ sender: Any) {
if let items = self.navigationItem.leftBarButtonItems {
var addItems = [UIBarButtonItem]()
addItems.append(contentsOf: items)
let barItem = UIBarButtonItem(title: "3", style: UIBarButtonItemStyle.plain, target: self, action: #selector(ViewController.leftAction(_:)))
addItems.append(barItem)
self.navigationItem.leftBarButtonItems = addItems
}
if let items = self.toolbar.items {
var addItems = [UIBarButtonItem]()
addItems.append(contentsOf: items)
let barItem = UIBarButtonItem(title: "L3", style: UIBarButtonItemStyle.plain, target: self, action: #selector(ViewController.leftAction(_:)))
addItems.insert(barItem, at: 2)
self.toolbar.setItems(addItems, animated: true)
}
}
}
This is the best solution I found so far:
Get the width of a view of another bar button item using key value coding. This is from Jeremy W. Sherman’s answer here.
Please note that it does not use any private API, see the discussion there. The worst thing that can happen is that the view property of the UIBarButtonItem cannot be accessed. In this case, I use a default value:
var leftBarButtonItems = self.navigationItem.leftBarButtonItems
let rotatingButton = UIButton(type: .custom)
rotatingButton.setImage(UIImage(named: "LocalizationInUseNoFix"), for: .normal)
rotatingButton.addTarget(self, action: #selector(localizationButtonTapped), for: .touchUpInside)
rotatingButton.rotateStart()
// Get the width of the bar button items if possible, else set default
let leftmostBarButtonItem = leftBarButtonItems![0]
let barButtonItemWidth: CGFloat
if let leftmostBarButtonItemView = leftmostBarButtonItem.value(forKey: "view") as? UIView {
barButtonItemWidth = leftmostBarButtonItemView.frame.size.width
} else {
barButtonItemWidth = 40.0
}
rotatingButton.widthAnchor.constraint(equalToConstant: barButtonItemWidth).isActive = true
let barButtonItem = UIBarButtonItem(customView: rotatingButton)
leftBarButtonItems![2] = barButtonItem
self.navigationItem.leftBarButtonItems = leftBarButtonItems
This is working fine for me. Best way is identify item to replace and change the content
#IBAction func changeLeftItems(_ sender: Any) {
if let items = self.toolbar.items {
var addItems = [UIBarButtonItem]()
addItems.append(contentsOf: items)
let barItem = UIBarButtonItem(title: "L5", style: UIBarButtonItemStyle.plain, target: self, action: #selector(ViewController.leftAction(_:)))
addItems.remove(at: 1)
addItems.insert(barItem, at: 1)
self.toolbar.setItems(addItems, animated: true)
}
}

Change BarButtonItem icon on click

I'm trying to create a counter. The idea is quite simple, you click on "play" button and once you click it should disappear and become a "pause" icon, which would trigger a different action.
I thought setting a var for counter status and changing the icon (with only one button) would do the trick but I don't have a clue how can I set the button image for "pause" or any other that appears in the drop down menu when you are creating it from the storyboard panel.
Here the code:
#IBOutlet weak var playButton: UIBarButtonItem!
var timer = NSTimer()
var currentStatus = "stopped"
#IBAction func playAction(sender: AnyObject) {
if (currentStatus == "stopped"){
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("increaseTimer"), userInfo: nil, repeats: true)
currentStatus = "running"
// change button icon (playButton) to Stop
}
else {
currentStatus = "stopped"
timer.invalidate()
// change button icon (playButton) to Play
}
}
You can set the button style like this:
//setButton to play
yourBarButtonItem = UIBarButtonItem(UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Play, target: self, action: "TheMethodThatTheButtonShouldCall"), animated: true)
//setButton to stop
yourBarButtonItem = UIBarButtonItem(UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Stop, target: self, action: "TheMethodThatTheButtonShouldCall"), animated: true)
You can set the button style with array like this:
func addCustomNavigationItemAtLeftAndRightSide(leftButtonItems:[UIBarButtonItem], rightButtonItems:[UIBarButtonItem]) {
self.navigationItem.leftBarButtonItems = leftButtonItems
self.navigationItem.rightBarButtonItems = rightButtonItems
}
You can use with style like this:
let leftButtonItem = UIBarButtonItem(image: UIImage(named: "ic_top_back"), style: .Plain, target: self, action: "onBackButtonClicked:")
addCustomNavigationItemAtLeftAndRightSide([leftButtonItem], rightButtonItems: [])

UIBarbutton 'Save' not appearing again after UIActivity Indicator stops on navigation Bar

There is a Save (System Item) on my navigation bar as BarButtonItem I am showing UIActivityIndicatorView on the navigation bar when user clicks this Save Button and I want to appear this Barbutton(Save) again on certain condition. First I think the problem is I am adding a indicator on customView so I don't need to hide the barbutton.It automatically hides itself after I start the indicator. But don't know now how to show Save Button again. or how can I remove the indicator from customView
This is how I am doing
#IBOutlet weak var saveButtonOutlet: UIBarButtonItem!
var activityIndicatorView:UIActivityIndicatorView!
func showActivityIndicator() {
activityIndicatorView = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.White)
activityIndicatorView.frame = CGRectMake(0, 0, 14, 14)
activityIndicatorView.color = UIColor().blueColorIOS()
activityIndicatorView.startAnimating()
let barButtonItem = UIBarButtonItem(customView: activityIndicatorView)
self.navigationItem.rightBarButtonItem = barButtonItem
}
#IBAction func saveButtonClicked(sender: UIBarButtonItem) {
showActivityIndicator()
ServerRequest.postToServer(url, params: params){
result, error in
if let result = result {
let code = result["code"] as? Int
print(result)
if (code==200){
dispatch_after(DISPATCH_TIME_NOW, dispatch_get_main_queue(), { ()->() in
self.activityIndicatorView.hidden = true
self.activityIndicatorView.hidesWhenStopped = true
//here want to show again "saveButtonOutlet"
})
}
}
}
}
}
So one way to do this is to create the Save button again, and setting the rightBarButtonItem again:
...
self.activityIndicatorView.hidden = true
self.activityIndicatorView.hidesWhenStopped = true
let barButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Save, target: self, action: "saveButtonClicked:")
self.navigationItem.rightBarButtonItem = barButtonItem
And I'd also replace self.activityIndicatorView.hidden = true with self.activityIndicatorView.stopAnimating() to properly use the hidesWhenStopped property.
I think all you need to do is reset the self.navigationItem.rightBarButtonItem to the saveButtonOutlet.
Worked right now for me.

hidesBarsOnTap - Navigation Bar hidden/displayed event?

I would like to set the background color of a view to black when the navigation bar is hidden, and to white when the navigation bar is displayed.
The property hidesBarsOnTap is set to true in viewDidLoad. This works fine:
navigationController?.hidesBarsOnTap = true
How can I be notified when the bars are hidden and displayed?
Sorry, I made a mistake. The following code does exactly what you want. If you have a toolbar, you can set it to hide as well.
class ViewController: UIViewController {
var hidden = false {
didSet {
if let nav = navigationController {
nav.setNavigationBarHidden(hidden, animated: true)
nav.setToolbarHidden(hidden, animated: true)
view.backgroundColor = hidden ? UIColor.blackColor() : UIColor.whiteColor()
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
let recognizer = UITapGestureRecognizer(target: self, action: "tap:")
view.addGestureRecognizer(recognizer)
}
func tap(recognizer: UITapGestureRecognizer) {
if recognizer.state == .Ended {
hidden = !hidden
}
}
}
since hidesBarsOnTap is of type boolean, we can easily use it to check and use it as option like in below example:
var set : Bool = navigationController?.hidesBarsOnTap //true or false
if (set){
//do what you want when set
}else{
//do what you want when it is not set
}

Resources