Question

I have a toolbar with various image buttons, created in Interface Builder.

I'd like to be able to programmatically replace one of the buttons with an activity indicator when pressed, and then put back the original button but change its color from white to yellow when the activity completes.

Is this possible with an IB built toolbar or must I look at building the whole toolbar programmatically and custom views?

Was it helpful?

Solution

Here is an example of what I did in a similar situation. I wanted to build the toolbar using Interface Builder but toggle one of the BarButtonItems based on whether or not it was "checked". In this example, there are a few key things to note. The following 2 member variables are defined for the class in the header file:

NSMutableArray *toolbarItems;
IBOutlet UIToolbar *toolbar;
NSUInteger checkUncheckIndex;

When I want to update the checked status, I call this function... Please note that there is a selector defined called checkUncheckClicked that is called when the particular button in the UIToolbar is clicked. And the UIToolbar is set up as an IBOutlet to toolbar. Alternately, you could hook up the UIBarButtonItem as an outlet itself and use that as your logic to identify the index of the button, or for that matter, you could hard-code the index of the button if things won't change over time. Finally, there is a checked.png and unchecked.png to alternate between that is included in the project.

- (void)updateBarButtonItemChecked:(BOOL)checked {
    if (toolbarItems == nil) {
        toolbarItems = [[NSMutableArray arrayWithArray:toolbar.items] retain];
        checkUncheckIndex = -1;

        for (NSUInteger i = 0; i < [toolbarItems count]; i++) {
            UIBarButtonItem *barButtonItem = [toolbarItems objectAtIndex:i];
            if (barButtonItem.action == @selector(checkUncheckClicked)) {
                favoriteIndex = i;
                break;
            }
        }
    }

    if (checkUncheckIndex != -1) {
        UIBarButtonItem *barButtonItem = [[[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:checked ? @"checked.png" : @"unchecked.png"] 
                                                                           style:UIBarButtonItemStylePlain target:self action:@selector(checkUncheckClicked)] autorelease];
        [toolbarItems replaceObjectAtIndex:checkUncheckIndex withObject:barButtonItem];

        toolbar.items = toolbarItems;
    }
}

And, of course toolbarItems and toolbar should be released in your dealloc for the class.

Hope this helps!

OTHER TIPS

Here is the approach I used It seemed to be much simpler to manage the toolbar entirely programatically so ....

In your view controller declare 1 or more sets of UIBarButtonItem items as property items also declare and hookup the toolbar as a UIToolbar property. Also declare 1 or more arrays to hold the items.

In the implementation In viewDidLoad alloc and set your UIBarButtonItems for example

       playButton = [[UIBarButtonItem alloc]
         initWithBarButtonSystemItem:UIBarButtonSystemItemPlay 
    target:self 
action:@selector(handlePlayClick)];

Flexible buttons (for alignment etc) are declared like this

   flexButton1 =[[UIBarButtonItem alloc]
 initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace 
target:nil action:nil];

There are several initMethods to handle the different types of buttons toolbars support. All follow a syntax similar to the above. Worth noting is the target and action settings. Target: would normally be self, action is the name of the function that button should trigger.

After alloc'ng your UIBarButtons add them to an array using initWithObjects.

Then to assign the buttons to the toolbar you would call

[toolbar setItems:<array name>];

Dont forget to dealloc your UIBarButtons and arrays at the end of your code.

Hope this helps. If you need more code let me know.

Rich D.

Swift

Much has changed since these answers have been posted. Here is a Swift 2.0 solution.

It matters not how the original UIBarButtonItem you are replacing has been created programmatically. All you need is the UIToolbar outlet. To replace, say, the 2nd item from the left, do this:

var toolbarItems = self.toolbar.items
let newItem = UIBarButtonItem(barButtonSystemItem: .Play, target: self, action: "play")
toolbarItems![1] = newItem
self.toolbar.setItems(toolbarItems, animated: true)

Swift has a much easier way. In my case, I am switching the play button with the pause button every touch.

@IBAction func playandPause(sender: UIBarButtonItem) { // Here we are creating an outlet. Hook this up to the bar button item.
    for (index, button) in toolbarItems!.enumerate() { // Enumerating through all the buttons
        if button === sender { // === operator is used to check if the two objects are the exact same instance in memory.
            var barButtonItem: UIBarButtonItem!
            if mediaplayer.playing {
                mediaplayer.pause()
                barButtonItem = UIBarButtonItem.init(barButtonSystemItem: .Play, target: self, action: #selector(playandPause(_:)))
            }else {
                mediaplayer.play()
                barButtonItem = UIBarButtonItem.init(barButtonSystemItem: .Pause, target: self, action: #selector(playandPause(_:)))
            }
            toolbarItems![index] = barButtonItem // Replace the old item with the new item.
            break // Break once we have found the button as it is unnecessary to complete the rest of the loop
        }
    }
}

I think it should be possible. You might either try creating an IBOutlet for that specific button in your ViewController class, and connect the button from IB to that outlet, or you can use the items property of that UIToolbar instance (you do have a reference to that, don't you?) and find the appropriate item in there, create a new NSArray with modified items, and set it back on that toolbar.items property.

HTH

A note on this - the toolbar will strip out any color in your icons, so you still won't be able to make it yellow. You'll need to change the image shape to indicate "on" instead.

Alternatively you'll need to load your BarButtonItems with UIButtons (use the initWithCustomView) and set the image of the button appropriately.

HTH

Try:

- (void)setTitle:(NSString *)title forItem:(int)item ofToolbar:(UIToolbar *)tb {
    NSMutableArray *newItems = [tb.items mutableCopy];
    UIBarButtonItem *old = [newItems objectAtIndex:1],
    *titled = [[UIBarButtonItem alloc] initWithTitle:title style:old.style target:old.target action:old.action];

    [newItems  replaceObjectAtIndex:1 withObject:titled];
    tb.items = newItems;

    [titled release];
}

For the entire toolbar that you created in IB (that is to say, not the individual toolbar items), create an IBOutlet:

@IBOutlet weak var toolbarThatYouMade: UIToolbar!

This is an array of individual toolbar items, so you would access the leftmost member (for example) with a [0] index:

toolbarThatYouMade.items![0].image = UIImage(named: "New Image")

This code assumes that you have an image named "New Image" in your assets.

You can then trigger an image change for a toolbar item without having to access that specific item itself; for example, if you were using this for something like a media player, you could toggle pause/play images from:
a) the Pause/Play button itself,
b) the Stop button,
c) when you are notified of a change of player state,
or
d) something else entirely. (Be brave! Be bold! Be something else that begins with 'b'!)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top