Question

Is there any way to set an animated image like the Apple spinning gear to an UIBarButtonItem?

I have tried this line of code but the animated gif image wont play:

myButton.image = [UIImage imageNamed:@"spinningGear.gif"];
Was it helpful?

Solution

Try creating a UIActivityIndicatorView and assigning it to your button with -[UIBarButtonItem initWithCustomView:].

OTHER TIPS

I don't think that's possible with UIBarButtonItem.

You might want to use customView for that (the property or initWithCustomView) and use UIImageView as that view. That still won't animate gif's "out of the box" (just checked).

If you do so you have two options:

  • use animatedImages from UIImageView class and use separate images for every frame (writing out of head - code might have some errors):

NSMutableArray * imgs = [NSMutableArray array];
for(int i = 0; i < NUMBER_OF_FRAMES; i++) {
    [imgs addObject: [UIImage imageNamed: [NSString stingWithFormat: @"anim%d.png", i]]];
}
UIImageView * imgview = [[UIImageView alloc] init];
imgview.animatedImages = imgs;
[imgview startAnimating];

I found that this line was incorrect:

[[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(0, 0, 20, 20)];

...the actual size of the default Refresh button from Apple is a little different. If you have other items doing auto-layout on that toolbar, you need to get the size right.

Unfortunately, Apple provides no API for finding out the size. By trial and error, it seems this is correct:

[[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(0, 0, 28, 28)];

I did this by setting the customView of the UIBarButtonItem to a UIButton with an icon image, then adding a UIActivityIndicator as a subview of the UIButton.

To set it up, I just dragged a UIButton onto the UIBarButtonItem in Interface Builder (you could also do that in your code). Then to display the activity indicator:

UIButton *customButton = (UIButton *)self.refreshButton.customView;
[customButton setImage:nil forState:UIControlStateNormal];
[customButton removeTarget:self action:@selector(buttonAction) forControlEvents:UIControlEventTouchUpInside];
[customButton addTarget:self action:@selector(altButtonAction) forControlEvents:UIControlEventTouchUpInside];
self.activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
self.activityIndicator.frame = CGRectMake(round((customButton.frame.size.width - 25) / 2), round((customButton.frame.size.height - 25) / 2), 25, 25);
self.activityIndicator.userInteractionEnabled = FALSE; // this allows the button to remain tappable
[customButton addSubview:self.activityIndicator];
[self.activityIndicator startAnimating];

And to return to the default button state:

UIButton *customButton = (UIButton *)self.refreshButton.customView;
[customButton setImage:[UIImage imageNamed:@"IconRefresh"] forState:UIControlStateNormal];
[customButton removeTarget:self action:@selector(altButtonAction) forControlEvents:UIControlEventTouchUpInside];
[customButton addTarget:self action:@selector(buttonAction) forControlEvents:UIControlEventTouchUpInside];
[self.activityIndicator removeFromSuperview];
[self.activityIndicator release];

A few notes:

  1. If you don't want to change the button action when it's in the "active" state, you can remove the addTarget and removeTarget lines.
  2. If you don't want the button to be tappable when it's in the "active" state, you can leave out the userInteractionEnabled line for the activity indicator (or remove the target and re-add it).
  3. A UIBarButtonItem with a customView will not display the button border. If you want this border, you'll have to make your own image and add it as the background image of the UIButton.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top