如何同时为 UIImageView 的图像和 UIImageView 本身设置动画?
Posted
技术标签:
【中文标题】如何同时为 UIImageView 的图像和 UIImageView 本身设置动画?【英文标题】:How do I simultaneously animate a UIImageView's image and the UIImageView itself? 【发布时间】:2013-04-15 22:31:59 【问题描述】:标题可能不太清楚,但我想做的是让 UIImageView 显示一系列图像(有点像 gif),我通过将 animationImages
设置为图像数组和然后打电话给[imageView startAnimating];
。这工作正常。我还有用 CABasicAnimation 移动 UIImageView 的代码,这个动画代码也可以正常工作。但是,当我尝试同时为 UIImageView 的图像设置动画并尝试移动 UIImageView 时,UIImageView 的图像停止动画。有解决办法吗?
这是我为 UIImageView 的内容制作动画的代码:
self.playerSprite = [[UIImageView alloc] initWithImage:[self.player.animationImages objectAtIndex:0]];
[self.playerSprite setFrame:CGRectMake(self.center.x, self.center.y, self.tileSet.constants.TILE_WIDTH, self.tileSet.constants.TILE_HEIGHT)];
self.playerSprite.animationImages = self.player.animationImages;
self.playerSprite.animationDuration = self.tileSet.constants.animationDuration;
self.playerSprite.animationRepeatCount = 0; //Makes it repeat indefinitely
这是我使用 CABasicAnimation 为 UIImageView 设置动画的代码:
float playerSpriteX = self.playerSprite.center.x;
float playerSpriteY = self.playerSprite.center.y;
CABasicAnimation *moveAnimation = [CABasicAnimation animation];
moveAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(playerSpriteX + TILE_WIDTH, playerSpriteY)];
[moveAnimation setDelegate:self];
[moveAnimation setFillMode:kCAFillModeForwards];
[moveAnimation setRemovedOnCompletion:NO];
[moveAnimation setDuration:MOVE_ANIMATION_DURATION];
[self.playerSprite.layer addAnimation:moveAnimation forKey:@"position"];
因此,当 UIImageView 的位置被动画化时,gif 效果不起作用。我的问题是我怎样才能让 UIImageView 在其位置被动画化的同时循环遍历一组图像?
【问题讨论】:
在我的回答中添加了一些细节和说明性视频。 【参考方案1】:这是推测,我根本没有测试过这个想法,但是您是否考虑过以与动画位置相同的方式实现图像动画,使用 CAKeyframeAnimation
?您需要从您的 UIImage
数组构造一个 CGImage
对象数组(设置关键帧动画的 values
属性),但它看起来非常简单:
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];
【讨论】:
如何将 CGImage 对象数组存储在数组中?我只是将它们投射到(id)
吗?
是的。您可以从UIImage
和[myImage CGImage]
获得CGImage
。
我非常同意这种方法,以至于我完全重写了自己的答案!
这个例子对我不起作用。使用资产目录中的 UIimage 将关键帧动画添加到 uiimageview,然后调用 startanimation 不会更改初始图像
@SeamusCampbell 如果我们有更多图像(300 张 720*720 的图像,每张 60Kb 大小),代码会崩溃,有什么替代方案或想法吗?因为将图像添加到数组会分配大量内存,因此内存崩溃!!!!【参考方案2】:
我刚刚做了类似的事情。我使用的代码如下所示:
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];
];
也许您遇到的问题是因为两个动画都在同一个线程上?
【讨论】:
【参考方案3】:您的“基本”问题从这一行开始:
CABasicAnimation *moveAnimation = [CABasicAnimation animation];
CABasicAnimation
对象 uses only a single keyframe。这意味着您正在制作动画的图层的内容只绘制一次,然后在动画期间使用该图像。
Seamus 建议使用CAKeyframeAnimation
是解决该问题的一种方法——关键帧动画将多次重绘动画层的内容,因此为每个关键帧绘制连续图像将为内容和位置设置动画.
【讨论】:
【参考方案4】:这不是制作精灵的好方法。我可以坚持认为您应该使用 OpenGL,但可能没有必要走那么远;你可以用一个层的核心动画来做这一切,我认为你最好这样做而不是尝试使用一个成熟的 UIImageView。
使用图层的核心动画,我可以让这个吃豆人精灵在张开和合上嘴的同时在屏幕上动画;这不就是你的想法吗?
这是一个展示动画的视频!
http://www.youtube.com/watch?v=WXCLc9ww8MI
然而创建动画的实际代码非常简单:只有两层动画(核心动画),一层用于变化的图像,另一层用于位置。
你应该不奖励这个答案!我现在只是在附和 Seamus Campbell 的话;我只是在他的回答中填写了一些细节。
好的,下面是生成上面链接的电影的代码:
- (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];
【讨论】:
对不起,我不接受。我试图点击链接(最初看起来很有希望),但我做不到。不过我会试试你的新代码。谢谢! 只是一个问题:CALayer 的“索引”属性是什么? 这就像我指出的教程中的sampleIndex
属性。基本上,随着index
的变化,CALayer 子类会通过重绘序列中的下一个图像来做出响应。
我现在提供了更精细的代码,与原始教程有很大不同。
再次修改,这次没有精灵图层子类。以上是关于如何同时为 UIImageView 的图像和 UIImageView 本身设置动画?的主要内容,如果未能解决你的问题,请参考以下文章
在 tableview 单元格中将图像设置为 UIImageView 会使滚动和旋转变慢
如何在 tableview 中为图像设置动画以同时扩展和打开另一个视图控制器?