我正在开发一个简单的应用程序,在用户移动滑块时动画图像。这可以通过单个图像轻松完成,但由于显而易见的原因,该方法效率低下。
目前,我将动画分为14张精灵表,每张16张图片。我创建了一个方法,使用CGImageCreateWithImageInRect来查找滑块指示的当前图像,并使用该图像更新图像视图。这有效,但不是流畅的。我想我理解为什么,但我不知道该怎么办。虽然我可以使用Cocos2d或OpenGL ES,但我很顽固并且相信没有它们就可以实现。我只是想知道如何。
以下是一些示例代码:
- (void)setUp{
NSString *string;
NSString *bundleString = [[NSBundle mainBundle] bundlePath];
dsRedPathArray = [[NSMutableArray alloc] initWithCapacity:15];
for (int i = 0; i < 14; i++)
{
string = [bundleString stringByAppendingFormat:@"/dsRedAni_%d.png", i];
[dsRedPathArray addObject:string];
}
//initial image starts at (0, 1) of image dsRedAni_9
currentImage = [UIImage imageWithContentsOfFile:[dsRedPathArray objectAtIndex:9]];
currentRef = CGImageCreateWithImageInRect(currentImage.CGImage, CGRectMake(495, 0, kModelWidth, kModelHeight));
modelView.image = [UIImage imageWithCGImage:currentRef];
}
- (IBAction)sliderMoved:(UISlider*)sender
{
[self animateModel:sender.value];
}
- (void)animateModel:(int)index
{
index += 1;
imageIndex = (index / 16) + 9;
if (imageIndex > 13)
{
imageIndex = -14 + imageIndex;
}
currentX = kModelWidth * (index % 4);
currentY = kModelHeight * ((index / 4) % 4);
currentRect = CGRectMake(currentX, currentY, kModelWidth, kModelHeight);
currentImage = [UIImage imageWithContentsOfFile:[dsRedPathArray objectAtIndex: (imageIndex)]];
currentRef = CGImageCreateWithImageInRect(currentImage.CGImage, currentRect);
modelView.image = [UIImage imageWithCGImage:currentRef];
}
提前感谢您的帮助。
答案 0 :(得分:4)
我终于找到了一种非常快速和有效的,如果非传统的方式,在没有API的任何外部帮助的情况下循环我的精灵表的每个部分。我没有花费时间和精力将图像切割成上下文或单个文件,而是发现以我所需的图像大小创建UIView然后将整个sprite表作为UIImageView添加到视图中更有效率。 。
当view.clipsToBounds设置为YES时,视图充当我的精灵表的掩码,将可见部分限制为我想在工作表上循环的每个图像的大小。为了给出动画的效果,我只需使用imageview.center将视图周围的精灵表移动到所需的图像坐标。因此,在一张包含16张图像的精灵表中,我只需要进行一次调用即可显示图像,然后在动画中的每一帧中移动它。
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setUp];
self.backgroundColor = [UIColor clearColor];
self.clipsToBounds = YES;
}
return self;
}
- (void)setUp
{
//assign |lastImageIndex| a number not equal to |imageIndex|
lastImageIndex = -1;
modelImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 1924, 1708)];
NSString *string;
NSString *bundleString = [[NSBundle mainBundle] bundlePath];
UIImage *image;
if (!imageArray)
{
imageArray = [[NSMutableArray alloc] init];
NSLog(@"Init egfp |imageArray|");
}
for (int i = 0; i < 10; i++)
{
string = [bundleString stringByAppendingFormat:@"/moleculeAni_%d.png", i];
image = [UIImage imageWithContentsOfFile:string];
[imageArray addObject:image];
if (i == 9)
{
NSLog(@"Filled egfp |imageCache|");
}
}
[self addSubview:modelImageView];
}
- (void)animateModel:(int)index
{
if (index != 1)
{
index -= 1;
}
imageIndex = (index / 16);
if (imageIndex < 9)
{
currentX = 962 - (481 * (index % 4));
currentY = 854 - (427 * ((index / 4) % 4));
}
else
{
currentX = 962 - (481 * (index % 4));
currentY = 427 - (427 * ((index / 4) % 4));
}
if (imageIndex != lastImageIndex)
{
if (imageIndex < 9 && onLastFrame)
{
modelImageView.frame = CGRectMake(0, 0, 1924, 1708);
onLastFrame = NO;
}
else if (imageIndex == 9 && !onLastFrame)
{
modelImageView.frame = CGRectMake(0, 0, 1924, 854);
onLastFrame = YES;
}
NSLog(@"Image: %d", imageIndex);
tempImage = [imageArray objectAtIndex:imageIndex];
modelImageView.image = tempImage;
}
modelImageView.center = CGPointMake(currentX, currentY);
lastImageIndex = imageIndex;
}
此处的大部分代码用于确定imageview需要移动的位置以显示正确的图像。这是采用我上面解释的方法,并将其分布在10个精灵表中,每个精灵表均匀分布16个图像(除了最后一个有8个)。当程序每隔16帧在图像之间交换时,唯一的减速就出现了。为了解决这个问题,我的控制器可以快速浏览另一个视图下方的所有图像(如窗帘),因此用户只能访问加载屏幕。图像循环后,窗帘视图将被移除,动画(由带滑块的用户控制)会像黄油一样移动。
答案 1 :(得分:2)
执行此操作的一种方法是使用CGImageCreateWithImageInRect剪切图像,就像您从上面开始一样。然后,将它们添加到数组中:
myArray addObject:[UIImage imageWithCGImage:currentRef];
接下来使用带有setAnimationImages的UIImageView,如下所示:
UIImageView *myAnimationImageView;
[myAnimationImageView setAnimationImages:myArray];
然后你可以开始动画了。
这里有一个很好的项目:https://github.com/r3econ/UIImage-Sprite-Additions