Search code examples
objective-canimationuiimageviewuiimagesubclassing

Subclassing UIImageView - animation images do not display or appear


I'm trying to subclass UIImageView in order to create an instance of the subclass which plays different animations, depending on a variable I send it. My initial code (before subclassing) for playing a specific 2 frame animation looked like this. 'bubbleAnimationTemp' is just a UIImageView object I declared in the header:

UIImage *animImage1 = [UIImage imageNamed:@"HappyAnim1.png"];
    UIImage *animImage2 = [UIImage imageNamed:@"HappyAnim2.png"];
    NSArray *images = [[NSArray alloc] initWithObjects:animImage1, animImage2, nil];
    bubbleAnimationTemp.animationImages = images;
    [images release];
    bubbleAnimationTemp.animationDuration = 0.5;
    bubbleAnimationTemp.animationRepeatCount = 5;
    [bubbleAnimationTemp startAnimating];

So then I tried subclassing UIImageView like so:

#import <UIKit/UIKit.h>
#import "Interaction.h"

@interface BubbleAnimation : UIImageView {
    UIImage *emotAnim1;
    UIImage *emotAnim2;
}

@property (nonatomic, retain) UIImage *emotAnim1;
@property (nonatomic, retain) UIImage *emotAnim2;

- (BubbleAnimation *)initWithMood:(NSString *)mood;

@end

#import "BubbleAnimation.h"

@implementation BubbleAnimation

@synthesize emotAnim1;
@synthesize emotAnim2;

- (BubbleAnimation *)initWithMood:(NSString *)mood {
    if (self = [super init]) {
        NSLog(@"Mood: %@", mood);
        if ([mood isEqualToString:kGood]) {
            emotAnim1 = [[UIImage alloc] initWithContentsOfFile:([[NSBundle mainBundle] pathForResource:@"HappyAnim1" ofType:@"png"])];
            emotAnim2 = [[UIImage alloc] initWithContentsOfFile:([[NSBundle mainBundle] pathForResource:@"HappyAnim2" ofType:@"png"])];
            //emotAnim1 = [UIImage imageNamed:@"HappyAnim1.png"];
            //emotAnim2 = [UIImage imageNamed:@"HappyAnim2.png"];
        }
        else if ([mood isEqualToString:kNeutral]) {
            emotAnim1 = [UIImage imageNamed:@"NeutralAnim1.png"];
            emotAnim2 = [UIImage imageNamed:@"NeutralAnim2.png"];
        }
        else {
            emotAnim1 = [UIImage imageNamed:@"SadAnim1.png"];
            emotAnim2 = [UIImage imageNamed:@"SadAnim2.png"];
        }
        NSArray *images = [[NSArray alloc] initWithObjects:emotAnim1, emotAnim2, nil];
        self.animationImages = images;
        [images release];
    }
    return self;
}

As you can see, I tried two different approaches for creating the UIImages to add to the UIImageView. But the problem I'm having is that nothing shows up when the animation plays.

I also tried simply copying the code from the first method into this subclass, so the process is essentially the same, but still nothing appears.

I've checked the documentation for notes on subclassing UIImageView but there doesn't seem to be anything I'm missing. I've made sure to change the 'UIImageView' object I placed in Interface Builder into a 'BubbleAnimation' object, so it's not that.

Any help as to why nothing appears would be very much appreciated. Thanks as always!

Michael

****************UPDATE****************

Well, thanks to Kalle's advice below, this is all fixed. However, now a similar issue is reoccurring and I wonder what I'm doing wrong.

Basically, I want to have a small heart that appears in the thought bubble, alongside the animation. I've added a UIImage to the BubbleAnimation class like so:

@interface BubbleAnimation : UIImageView {
    UIImage     *emotAnim1;
    UIImage     *emotAnim2;
    UIImage     *heart;
}

@property (nonatomic, retain) UIImage *heart;

- (void)setMood:(NSString *)mood;

@end

And synthesise it in the implementation as usual. Then I set the heart to the correct colour in the setMood method:

- (void)setMood:(NSString *)mood {
    if ([mood isEqualToString:kGood]) {
        emotAnim1 = [UIImage imageNamed:@"Good1.png"];
        emotAnim2 = [UIImage imageNamed:@"Good2.png"];
        self.heart = [UIImage imageNamed:@"HeartRed.png"];
    }
    else if ...

In IB, I've added a hidden UIImageView object and linked it to a UIImageView IBOutlet in my ViewController called bubbleHeart. When the thought bubble appears, I use the following code to display the animations and the heart:

    [bubbleAnimation setMood:charachter.mood];
self.bubbleHeart.image = bubbleAnimation.heart;
        bubbleAnimation.animationDuration = kAnimationDuration;
        bubbleAnimation.animationRepeatCount = kAnimationRepeatCount;
        [bubbleAnimation startAnimating];
        bubbleHeart.hidden = FALSE;

The problem is, the animation appears, but the little heart doesn't. I've tried various approaches - I created the UIImageView in the BubbleAnimation class, instead of using a UIImage, and tried initialising it in various different ways, but no joy. If I call something like self.bubbleHeart = [[UIImageView alloc] initWithImage:bubbleAnimation.heart]; then presumably I'm reinitialising the variable so that doesn't work. Any idea why it's not appearing?

Many thanks!

Michael


Solution

  • In your original code, you never allocated a new instance of BubbleAnimation, and that's why it worked fine.

    You have an object in the XIB file which is the BubbleAnimation object, and that's all fine, but the problem is that you're allocating a new instance of BubbleAnimation instead of using the one you have in your revised code.

    Even if you were to use the one you have, you'd have to change the init method, since the system will call initWithCoder:, not initWithMood:.

    The best thing is most likely to change the init function to something else, e.g. a setMood:, which modifies the image view. Then you re-use the same image view every time.

    Then you'd just set it up using something like...

    [bubbleAnimation setMood:character.mood];
    bubbleAnimation.animationDuration = 0.5; 
    bubbleAnimation.animationRepeatCount = 5; 
    [bubbleAnimation startAnimating];