123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221 |
- //
- // YLImageView.m
- // YLGIFImage
- //
- // Created by Yong Li on 14-3-2.
- // Copyright (c) 2014年 Yong Li. All rights reserved.
- //
- #import "YLImageView.h"
- #import "YLGIFImage.h"
- #import <QuartzCore/QuartzCore.h>
- @interface YLImageView ()
- @property (nonatomic, strong) YLGIFImage *animatedImage;
- @property (nonatomic, strong) CADisplayLink *displayLink;
- @property (nonatomic) NSTimeInterval accumulator;
- @property (nonatomic) NSUInteger currentFrameIndex;
- @property (nonatomic, strong) UIImage* currentFrame;
- @property (nonatomic) NSUInteger loopCountdown;
- @end
- @implementation YLImageView
- const NSTimeInterval kMaxTimeStep = 1; // note: To avoid spiral-o-death
- @synthesize runLoopMode = _runLoopMode;
- @synthesize displayLink = _displayLink;
- - (id)init
- {
- self = [super init];
- if (self) {
- self.currentFrameIndex = 0;
- }
- return self;
- }
- - (CADisplayLink *)displayLink
- {
- if (self.superview) {
- if (!_displayLink && self.animatedImage) {
- _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(changeKeyframe:)];
- [_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:self.runLoopMode];
- }
- } else {
- [_displayLink invalidate];
- _displayLink = nil;
- }
- return _displayLink;
- }
- - (NSString *)runLoopMode
- {
- return _runLoopMode ?: NSRunLoopCommonModes;
- }
- - (void)setRunLoopMode:(NSString *)runLoopMode
- {
- if (runLoopMode != _runLoopMode) {
- [self stopAnimating];
-
- NSRunLoop *runloop = [NSRunLoop mainRunLoop];
- [self.displayLink removeFromRunLoop:runloop forMode:_runLoopMode];
- [self.displayLink addToRunLoop:runloop forMode:runLoopMode];
-
- _runLoopMode = runLoopMode;
-
- [self startAnimating];
- }
- }
- - (void)setImage:(UIImage *)image
- {
- if (image == self.image) {
- return;
- }
-
- [self stopAnimating];
-
- self.currentFrameIndex = 0;
- self.loopCountdown = 0;
- self.accumulator = 0;
-
- if ([image isKindOfClass:[YLGIFImage class]] && image.images) {
- if([image.images[0] isKindOfClass:UIImage.class])
- [super setImage:image.images[0]];
- else
- [super setImage:nil];
- self.currentFrame = nil;
- self.animatedImage = (YLGIFImage *)image;
- self.loopCountdown = self.animatedImage.loopCount ?: NSUIntegerMax;
- [self startAnimating];
- } else {
- self.animatedImage = nil;
- [super setImage:image];
- }
- [self.layer setNeedsDisplay];
- }
- - (void)setAnimatedImage:(YLGIFImage *)animatedImage
- {
- _animatedImage = animatedImage;
- if (animatedImage == nil) {
- self.layer.contents = nil;
- }
- }
- - (BOOL)isAnimating
- {
- return [super isAnimating] || (self.displayLink && !self.displayLink.isPaused);
- }
- - (void)stopAnimating
- {
- if (!self.animatedImage) {
- [super stopAnimating];
- return;
- }
-
- self.loopCountdown = 0;
-
- self.displayLink.paused = YES;
- }
- - (void)startAnimating
- {
- if (!self.animatedImage) {
- [super startAnimating];
- return;
- }
-
- if (self.isAnimating) {
- return;
- }
-
- self.loopCountdown = self.animatedImage.loopCount ?: NSUIntegerMax;
-
- self.displayLink.paused = NO;
- }
- - (void)changeKeyframe:(CADisplayLink *)displayLink
- {
- if (self.currentFrameIndex >= [self.animatedImage.images count]) {
- return;
- }
- self.accumulator += fmin(displayLink.duration, kMaxTimeStep);
-
- while (self.accumulator >= self.animatedImage.frameDurations[self.currentFrameIndex]) {
- self.accumulator -= self.animatedImage.frameDurations[self.currentFrameIndex];
- if (++self.currentFrameIndex >= [self.animatedImage.images count]) {
- if (--self.loopCountdown == 0) {
- [self stopAnimating];
- return;
- }
- self.currentFrameIndex = 0;
- }
- self.currentFrameIndex = MIN(self.currentFrameIndex, [self.animatedImage.images count] - 1);
- self.currentFrame = [self.animatedImage getFrameWithIndex:self.currentFrameIndex];
- [self.layer setNeedsDisplay];
- }
- }
- - (void)displayLayer:(CALayer *)layer
- {
- if (!self.animatedImage || [self.animatedImage.images count] == 0) {
- return;
- }
- //NSLog(@"display index: %luu", (unsigned long)self.currentFrameIndex);
- if(self.currentFrame && ![self.currentFrame isKindOfClass:[NSNull class]])
- layer.contents = (__bridge id)([self.currentFrame CGImage]);
- }
- - (void)didMoveToWindow
- {
- [super didMoveToWindow];
- if (self.window) {
- [self startAnimating];
- } else {
- dispatch_async(dispatch_get_main_queue(), ^{
- if (!self.window) {
- [self stopAnimating];
- }
- });
- }
- }
- - (void)didMoveToSuperview
- {
- [super didMoveToSuperview];
- if (self.superview) {
- //Has a superview, make sure it has a displayLink
- [self displayLink];
- } else {
- //Doesn't have superview, let's check later if we need to remove the displayLink
- dispatch_async(dispatch_get_main_queue(), ^{
- [self displayLink];
- });
- }
- }
- - (void)setHighlighted:(BOOL)highlighted
- {
- if (!self.animatedImage) {
- [super setHighlighted:highlighted];
- }
- }
- - (UIImage *)image
- {
- return self.animatedImage ?: [super image];
- }
- - (CGSize)sizeThatFits:(CGSize)size
- {
- return self.image.size;
- }
- @end
|