How do I simultaneously animate a UIImageView's image and the UIImageView itself?

后端 未结 4 1946
余生分开走
余生分开走 2020-12-16 08:26

The title may not be so clear, but what I want to do is to make the UIImageView display a series of images (sort of like a gif) and I do this by setting the animationI

相关标签:
4条回答
  • 2020-12-16 08:51

    This is not a good way to make a sprite. I could insist that you should be using OpenGL, but there may be no need to go that far; you can do it all with Core Animation of a layer, and I think you'll be better off doing that than trying to use a full-fledged UIImageView.

    Using Core Animation of a layer, I was able to make this PacMan sprite animate across the screen while opening and closing his mouth; isn't that the sort of thing you had in mind?

    enter image description here

    Here is a video showing the animation!

    http://www.youtube.com/watch?v=WXCLc9ww8MI

    And yet the actual code creating the animation is extremely simple: just two layer animations (Core Animation), one for the changing image, the other for the position.

    You should not award this answer the bounty! I am now merely echoing what Seamus Campbell said; I'm just filling out the details of his answer a little.

    Okay, so here's the code that generates the movie linked above:

    - (void)viewDidLoad {
        [super viewDidLoad];
        // construct arr, an array of CGImage (omitted)
        // it happens I've got 5 images, the last being the same as the first
        self.images = [arr copy];
        // place sprite into the interface
        self.sprite = [CALayer new];
        self.sprite.frame = CGRectMake(30,30,24,24);
        self.sprite.contentsScale = [UIScreen mainScreen].scale;
        [self.view.layer addSublayer:self.sprite];
        self.sprite.contents = self.images[0];
    }
    
    - (void)animate {
        CAKeyframeAnimation* anim = 
            [CAKeyframeAnimation animationWithKeyPath:@"contents"];
        anim.values = self.images;
        anim.keyTimes = @[@0,@0.25,@0.5,@0.75,@1];
        anim.calculationMode = kCAAnimationDiscrete;
        anim.duration = 1.5;
        anim.repeatCount = HUGE_VALF;
    
        CABasicAnimation* anim2 = 
            [CABasicAnimation animationWithKeyPath:@"position"];
        anim2.duration = 10;
        anim2.toValue = [NSValue valueWithCGPoint: CGPointMake(350,30)];
    
        CAAnimationGroup* group = [CAAnimationGroup animation];
        group.animations = @[anim, anim2];
        group.duration = 10;
    
        [self.sprite addAnimation:group forKey:nil];
    }
    
    0 讨论(0)
  • 2020-12-16 09:00

    This is speculation and I haven't tested this idea at all, but have you considered implementing the image animation in the same fashion you're animating the position, with a CAKeyframeAnimation? You'd need to construct an array of CGImage objects from your UIImage array (to set the values property of the keyframe animation) but it looks like a pretty straightforward conversion:

    CAKeyframeAnimation *imageAnimation = [CAKeyframeAnimation animation];
    imageAnimation.calculationMode = kCAAnimationDiscrete; // or maybe kCAAnimationPaced
    imageAnimation.duration = self.tileSet.constants.animationDuration;
    imageAnimation.repeatCount = HUGE_VALF;
    // the following method will need to be implemented to cast your UIImage array to CGImages
    imageAnimation.values = [self animationCGImagesArray];
    [self.playerSprite.layer addAnimation:imageAnimation forKey:@"contents"];
    
    -(NSArray*)animationCGImagesArray {
        NSMutableArray *array = [NSMutableArray arrayWithCapacity:[self.player.animationImages count]];
        for (UIImage *image in self.player.animationImages) {
            [array addObject:(id)[image CGImage]];
        }
        return [NSArray arrayWithArray:array];
    }
    
    0 讨论(0)
  • 2020-12-16 09:02

    Your "basic" problem starts on this line:

    CABasicAnimation *moveAnimation = [CABasicAnimation animation];
    

    A CABasicAnimation object uses only a single keyframe. That means that the content of the layer that you're animating is drawn once, and then that image is used for the duration of the animation.

    Using a CAKeyframeAnimation as Seamus suggests is one way to deal with the problem -- a keyframe animation will redraw the content of the animated layer multiple times, so drawing successive images for each keyframe will animate the content as well as position.

    0 讨论(0)
  • 2020-12-16 09:06

    I've just done something similar. The code I used looks like this:

        CGRect r = ziv.frame;
        r.origin.x += WrongDistance;
        [ziv startAnimating];
        [UIView animateWithDuration:3.0 animations:^(void){
            [ziv setFrame:r];
        } completion:^(BOOL finished){
    
            [ziv stopAnimating];
    
            if (finished){
                // not canceled in flight
                if (NumWrong == MaxWrong)
                    [self endOfGame:NO];
                else
                    [self nextRound:self];
            }
        }];
    

    Perhaps the issue you're running into is because both animations are on the same thread?

    0 讨论(0)
提交回复
热议问题