将CALayer的内容设置为GIF动画? [英] Set contents of CALayer to animated GIF?
问题描述
是否可以将CALayer
的内容设置为动画GIF并显示该动画?我知道我可以将内容设置为这样的图像:
Is it possible to set the contents of a CALayer
to an animated GIF and have it display that animation? I know that I can set the contents to an image like so:
CALayer* subLayer = [CALayer layer];
NSImage *image = [[NSImage alloc] initWithData:data];
subLayer.contents = image;
将显示图像,但是如果已设置动画,则不会显示动画.是获取GIF的各个帧,获取帧率,然后根据帧率更改子层的content
的唯一解决方案吗?还是我忽略了一个更简单的方法?
And the image will show, but if it's animated, the animation will not display. Is the only solution to get the individual frames for the GIF, get the frame rate, then change the content
of the sublayer according to the frame rate? Or is there a much simpler method that I'm overlooking?
推荐答案
好吧,我想这并不难做到.基本上我会检查图像是否为GIF:
Well, okay, I guess this isn't that hard to do. Basically I check to see if the image is a GIF:
if ([format isEqualToString:@"gif"]){
CAKeyframeAnimation *animation = [self createGIFAnimation:data];
[subLayer addAnimation:animation forKey:@"contents"];
}
如您所见,我正在调用自定义的createGIFAnimation
方法,如下所示:
And as you can see, I'm calling my custom createGIFAnimation
method, which looks like this:
- (CAKeyframeAnimation *)createGIFAnimation:(NSData *)data{
NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithData:data];
CGImageSourceRef src = CGImageSourceCreateWithData((__bridge CFDataRef)(data), nil);
NSNumber *frameCount = [rep valueForProperty:@"NSImageFrameCount"];
// Total loop time
float time = 0;
// Arrays
NSMutableArray *framesArray = [NSMutableArray array];
NSMutableArray *tempTimesArray = [NSMutableArray array];
// Loop
for (int i = 0; i < frameCount.intValue; i++){
// Frame default duration
float frameDuration = 0.1f;
// Frame duration
CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(src,i,nil);
NSDictionary *frameProperties = (__bridge NSDictionary*)cfFrameProperties;
NSDictionary *gifProperties = frameProperties[(NSString*)kCGImagePropertyGIFDictionary];
// Use kCGImagePropertyGIFUnclampedDelayTime or kCGImagePropertyGIFDelayTime
NSNumber *delayTimeUnclampedProp = gifProperties[(NSString*)kCGImagePropertyGIFUnclampedDelayTime];
if(delayTimeUnclampedProp) {
frameDuration = [delayTimeUnclampedProp floatValue];
} else {
NSNumber *delayTimeProp = gifProperties[(NSString*)kCGImagePropertyGIFDelayTime];
if(delayTimeProp) {
frameDuration = [delayTimeProp floatValue];
}
}
// Make sure its not too small
if (frameDuration < 0.011f){
frameDuration = 0.100f;
}
[tempTimesArray addObject:[NSNumber numberWithFloat:frameDuration]];
// Release
CFRelease(cfFrameProperties);
// Add frame to array of frames
CGImageRef frame = CGImageSourceCreateImageAtIndex(src, i, nil);
[framesArray addObject:(__bridge id)(frame)];
// Compile total loop time
time = time + frameDuration;
}
NSMutableArray *timesArray = [NSMutableArray array];
float base = 0;
for (NSNumber* duration in tempTimesArray){
//duration = [NSNumber numberWithFloat:(duration.floatValue/time) + base];
base = base + (duration.floatValue/time);
[timesArray addObject:[NSNumber numberWithFloat:base]];
}
// Create animation
CAKeyframeAnimation* animation = [CAKeyframeAnimation animationWithKeyPath:@"contents"];
animation.duration = time;
animation.repeatCount = HUGE_VALF;
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;
animation.values = framesArray;
animation.keyTimes = timesArray;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
animation.calculationMode = kCAAnimationDiscrete;
return animation;
}
非常简单,尽管我希望获得一些改进技巧.
Pretty straightforward, although I would love some tips on how to improve it.
这篇关于将CALayer的内容设置为GIF动画?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!