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.

Ckoeny
  • 217
  • 1
  • 2
  • 5

9 Answers9

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

Michael Dautermann
  • 88,797
  • 17
  • 166
  • 215
  • 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? – Ckoeny Nov 25 '11 at 16:46
  • 1
    I have solved the issue by using a UIImageView as the customView. do set the userInteractionEnabled to TRUE. – Ckoeny Nov 25 '11 at 20:31
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)
Patrick
  • 415
  • 5
  • 11
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];
Cameron Lowell Palmer
  • 21,528
  • 7
  • 125
  • 126
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 :)

ThePunisher
  • 410
  • 1
  • 4
  • 14
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;
}
SmileBot
  • 19,393
  • 7
  • 65
  • 62
  • 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! – Mark Jul 14 '14 at 16:43
  • @Mark 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. – SmileBot Jul 14 '14 at 18:54
  • 1
    Thanks @cocoanut, this is much better. – Mark Jul 14 '14 at 21:25
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.

leanne
  • 7,940
  • 48
  • 77
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.

Allan Scofield
  • 1,884
  • 18
  • 14
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).

Akhrameev
  • 325
  • 4
  • 12
-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.

Stephen
  • 1,737
  • 2
  • 26
  • 37
the monk
  • 389
  • 4
  • 14
  • -1 the question confirms that isSelected method is available on UIButton, but it specifically asks for the equivalent on UIBarButtonItem. – martin jakubik Oct 17 '12 at 10:07