programmatically highlight UIBarButtonItem
Asked Answered
B

9

18

after tapping the 'record' BarButtonItem I would like to keep it programmatically highlighted until the recording is over. The highlighting graphics of iOS are very good, therefor I would like to remain or set that state.

Up to now I found 'setSelected' and 'setHighlighted' but these do not work on a UIBarButtonItem. Any suggestions on how to solve this? Thank you in advance, Koen.

Beamy answered 25/11, 2011 at 10:33 Comment(0)
A
11

setSelected and setHighlighted work fine on UIControls, but not UIBarButtonItems (which are not UIControls).

I'd recommend using UIBarButtonItem's - (void)setBackgroundImage:(UIImage *)backgroundImage forState:(UIControlState)state barMetrics:(UIBarMetrics)barMetrics (documentation linked) method to change the background image to something that mimics highlighting.

You can also set a custom UIView on the item which also mimics highlighting (see the customView property).

Agneta answered 25/11, 2011 at 10:44 Comment(2)
Hi Michael, do you have some sample code on using a customView in the UIBarButtonItem? I have tried implementing it but ended with a black rectangle where I wanted it transparent. Any suggestions?Beamy
I have solved the issue by using a UIImageView as the customView. do set the userInteractionEnabled to TRUE.Beamy
V
6

If you absolutely want to use the default graphics, you could initialize your button item as

UIBarButtonItem *toggleButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"MyButton" 
                                                                     style:UIBarButtonItemStyleBordered 
                                                                    target:someObject 
                                                                    action:@selector(doSomething:)];

and toggle it with

toggleButtonItem.style = (toggleButtonItem.style == UIBarButtonItemStyleBordered) 
                         ? UIBarButtonItemStyleDone : UIBarButtonItemStyleBordered;

You would also need to use the style property to read the current state.

BOOL isSelected = (toggleButtonItem.style == UIBarButtonItemStyleDone)
Vashtivashtia answered 3/8, 2012 at 15:30 Comment(1)
Alas, Bordered is deprecated.Colene
A
6

If you add a UIBarButtonItem with a UIButton backing it, you can just ask for the CustomView.

UIBarButtonItem with a backing UIButton

UIButton *button = (UIButton *)[self.barButtonItem customView];
[button setSelected:YES];
Abdominal answered 7/10, 2013 at 12:41 Comment(3)
This answer works great, the only issue is that you need to cast [self.barButtonItem customView]; to the UIButton. (UIButton *)self.barButtonItem.customView; Otherwise works great.Davide
Yes, the cast is necessary, but hardly serious. Did you down vote this answer for that? Just edit it.Abdominal
I upvoted it. Not sure where the downvote came from.Davide
L
4

You create an outlet of this button for example btnMoreOut and you do:

btnMoreOut.tintColor = [UIColor colorWithRed:0.882 green:0.722 blue:0.169 alpha:1];

I hope this helps..Good luck :)

Lingenfelter answered 3/12, 2012 at 12:31 Comment(1)
Brilliant. Works perfectly for my implementation! :)Virulent
D
2

1) Get a reference to your bar button.

2) Using the style property, assign it to UIBarButtonItemStyleDone, or UIBarButtonItemStylePlain on the basis of some state.

NB. You can get the state in various ways. For instance, using NSUserDefaults, save a key value pair there. Pull out the value, and grab some BOOL representation to test against. Then write this line:

 self.myButton.style = self.someState ? UIBarButtonItemStyleDone : UIBarButtonItemStylePlain;

Or with the defaults all nested like this:

self.myButton.style = [[NSUserDefaults standardUserDefaults] 
boolForKey:@"someKey"] ? UIBarButtonItemStyleDone : UIBarButtonItemStylePlain;

Without the ternary operator:

if ([[NSUserDefaults standardUserDefaults] 
    boolForKey:@"someKey"]) {
self.myButton.style = UIBarButtonItemStyleDone; 
} else {
self.myButton.style = UIBarButtonItemStylePlain;
}
Deweydewhirst answered 14/7, 2014 at 15:4 Comment(2)
I'm getting tired with asking people to add explanations and there is no "code only" option while there is a "link only" option. Please add explanations!Submersed
@Submersed Ok, let me know if that's enough context for you then. Does it make sense now? I'm using the ternary operator which might be throwing you.Deweydewhirst
D
1

p.a.'s answer, converted for Xcode 9, Swift 4.
The idea is that the .done style highlights - or bolds, in Swift 4 - the button text.

Initialize the button item in an un-highlighted state:

let toggleButtonItem = UIBarButtonItem(title: "MyButton",
                                       style: .plain,
                                       target: self,
                                       action: #selector(doSomething))

Toggle the button item to a highlighted state using a ternary operator, like so:

toggleButtonItem.style = (toggleButtonItem.style == .plain) ?
                         toggleButtonItem.style = .done : toggleButtonItem.style = .plain

Or, alternatively, toggle the highlight state with a regular if/else statement like this instead:

if toggleButtonItem.style == .plain {
    toggleButtonItem.style = .done
}
else {
    toggleButtonItem.style = .plain
}

And, to set up a boolean value to check if the button item is highlighted:

var isHighlighted: Bool = (toggleButtonItem.style == .done)

Notes:

  • The bordered style was deprecated in iOS 8, so I used .plain here instead. They both present the button item's text in an unhighlighted state.
  • The #selector function must either be an @IBAction, or it must be prefixed with @objc, to avoid "Objective-C inference" issues. For example:

    @objc func doSomething() { ... }
    

    or, if you've connected an action to the button item:

    @IBAction func doSomething() { ... }
    

    Both of these function declarations tell the compiler that they're using Objective-C-based functionality. This is required because #selector is an Objective-C thing under the hood, and in Swift 4 you have to state this, rather than letting the compiler infer what's going on as it has done previously.

Deathbed answered 7/12, 2017 at 19:30 Comment(0)
S
0

You can try this (Swift):

    func setupInterface(){

    var myButton = UIBarButtonItem()
    if (your_condition){
      myButton = UIBarButtonItem(image: UIImage(named: "img_selected"), style: .Plain, target: self, action: Selector("DoSomething:"))
    }
    else{
        myButton = UIBarButtonItem(image: UIImage(named: "img_unselected"), style: .Plain, target: self, action: Selector("DoSomething:"))
    }
    navigationItem.rightBarButtonItem = myButton
  }

Call setupInterface() in ViewDidLoad and another function in your code.

Senzer answered 28/1, 2016 at 17:19 Comment(0)
O
0

If you wanna change just title attributes (for example, title color), you can call setTitleTextAttributes:forState:

For me, it works more stable than setTintColor: (changing tint color breaks during unwind segue push animation).

Opposable answered 15/6, 2016 at 11:21 Comment(0)
C
-2

You can use two images for the two states of the button like for one state "UIControlStateNormal" you can use an image for the normal condition.

And then when the button is pressed, set the other image which shows it pressed, then the image with a check using isSelected method of UIButton.

Hope this makes some sense to you.

Cruck answered 25/11, 2011 at 10:47 Comment(1)
-1 the question confirms that isSelected method is available on UIButton, but it specifically asks for the equivalent on UIBarButtonItem.Idiocy

© 2022 - 2024 — McMap. All rights reserved.