18
votes

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.

9

9 Answers

11
votes

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).

6
votes

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)
6
votes

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];
4
votes

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 :)

2
votes

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;
}
1
votes

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.

0
votes

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.

0
votes

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).

-2
votes

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.