2
0

YLImageView.m 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. //
  2. // YLImageView.m
  3. // YLGIFImage
  4. //
  5. // Created by Yong Li on 14-3-2.
  6. // Copyright (c) 2014年 Yong Li. All rights reserved.
  7. //
  8. #import "YLImageView.h"
  9. #import "YLGIFImage.h"
  10. #import <QuartzCore/QuartzCore.h>
  11. @interface YLImageView ()
  12. @property (nonatomic, strong) YLGIFImage *animatedImage;
  13. @property (nonatomic, strong) CADisplayLink *displayLink;
  14. @property (nonatomic) NSTimeInterval accumulator;
  15. @property (nonatomic) NSUInteger currentFrameIndex;
  16. @property (nonatomic, strong) UIImage* currentFrame;
  17. @property (nonatomic) NSUInteger loopCountdown;
  18. @end
  19. @implementation YLImageView
  20. const NSTimeInterval kMaxTimeStep = 1; // note: To avoid spiral-o-death
  21. @synthesize runLoopMode = _runLoopMode;
  22. @synthesize displayLink = _displayLink;
  23. - (id)init
  24. {
  25. self = [super init];
  26. if (self) {
  27. self.currentFrameIndex = 0;
  28. }
  29. return self;
  30. }
  31. - (CADisplayLink *)displayLink
  32. {
  33. if (self.superview) {
  34. if (!_displayLink && self.animatedImage) {
  35. _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(changeKeyframe:)];
  36. [_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:self.runLoopMode];
  37. }
  38. } else {
  39. [_displayLink invalidate];
  40. _displayLink = nil;
  41. }
  42. return _displayLink;
  43. }
  44. - (NSString *)runLoopMode
  45. {
  46. return _runLoopMode ?: NSRunLoopCommonModes;
  47. }
  48. - (void)setRunLoopMode:(NSString *)runLoopMode
  49. {
  50. if (runLoopMode != _runLoopMode) {
  51. [self stopAnimating];
  52. NSRunLoop *runloop = [NSRunLoop mainRunLoop];
  53. [self.displayLink removeFromRunLoop:runloop forMode:_runLoopMode];
  54. [self.displayLink addToRunLoop:runloop forMode:runLoopMode];
  55. _runLoopMode = runLoopMode;
  56. [self startAnimating];
  57. }
  58. }
  59. - (void)setImage:(UIImage *)image
  60. {
  61. if (image == self.image) {
  62. return;
  63. }
  64. [self stopAnimating];
  65. self.currentFrameIndex = 0;
  66. self.loopCountdown = 0;
  67. self.accumulator = 0;
  68. if ([image isKindOfClass:[YLGIFImage class]] && image.images) {
  69. if([image.images[0] isKindOfClass:UIImage.class])
  70. [super setImage:image.images[0]];
  71. else
  72. [super setImage:nil];
  73. self.currentFrame = nil;
  74. self.animatedImage = (YLGIFImage *)image;
  75. self.loopCountdown = self.animatedImage.loopCount ?: NSUIntegerMax;
  76. [self startAnimating];
  77. } else {
  78. self.animatedImage = nil;
  79. [super setImage:image];
  80. }
  81. [self.layer setNeedsDisplay];
  82. }
  83. - (void)setAnimatedImage:(YLGIFImage *)animatedImage
  84. {
  85. _animatedImage = animatedImage;
  86. if (animatedImage == nil) {
  87. self.layer.contents = nil;
  88. }
  89. }
  90. - (BOOL)isAnimating
  91. {
  92. return [super isAnimating] || (self.displayLink && !self.displayLink.isPaused);
  93. }
  94. - (void)stopAnimating
  95. {
  96. if (!self.animatedImage) {
  97. [super stopAnimating];
  98. return;
  99. }
  100. self.loopCountdown = 0;
  101. self.displayLink.paused = YES;
  102. }
  103. - (void)startAnimating
  104. {
  105. if (!self.animatedImage) {
  106. [super startAnimating];
  107. return;
  108. }
  109. if (self.isAnimating) {
  110. return;
  111. }
  112. self.loopCountdown = self.animatedImage.loopCount ?: NSUIntegerMax;
  113. self.displayLink.paused = NO;
  114. }
  115. - (void)changeKeyframe:(CADisplayLink *)displayLink
  116. {
  117. if (self.currentFrameIndex >= [self.animatedImage.images count]) {
  118. return;
  119. }
  120. self.accumulator += fmin(displayLink.duration, kMaxTimeStep);
  121. while (self.accumulator >= self.animatedImage.frameDurations[self.currentFrameIndex]) {
  122. self.accumulator -= self.animatedImage.frameDurations[self.currentFrameIndex];
  123. if (++self.currentFrameIndex >= [self.animatedImage.images count]) {
  124. if (--self.loopCountdown == 0) {
  125. [self stopAnimating];
  126. return;
  127. }
  128. self.currentFrameIndex = 0;
  129. }
  130. self.currentFrameIndex = MIN(self.currentFrameIndex, [self.animatedImage.images count] - 1);
  131. self.currentFrame = [self.animatedImage getFrameWithIndex:self.currentFrameIndex];
  132. [self.layer setNeedsDisplay];
  133. }
  134. }
  135. - (void)displayLayer:(CALayer *)layer
  136. {
  137. if (!self.animatedImage || [self.animatedImage.images count] == 0) {
  138. return;
  139. }
  140. //NSLog(@"display index: %luu", (unsigned long)self.currentFrameIndex);
  141. if(self.currentFrame && ![self.currentFrame isKindOfClass:[NSNull class]])
  142. layer.contents = (__bridge id)([self.currentFrame CGImage]);
  143. }
  144. - (void)didMoveToWindow
  145. {
  146. [super didMoveToWindow];
  147. if (self.window) {
  148. [self startAnimating];
  149. } else {
  150. dispatch_async(dispatch_get_main_queue(), ^{
  151. if (!self.window) {
  152. [self stopAnimating];
  153. }
  154. });
  155. }
  156. }
  157. - (void)didMoveToSuperview
  158. {
  159. [super didMoveToSuperview];
  160. if (self.superview) {
  161. //Has a superview, make sure it has a displayLink
  162. [self displayLink];
  163. } else {
  164. //Doesn't have superview, let's check later if we need to remove the displayLink
  165. dispatch_async(dispatch_get_main_queue(), ^{
  166. [self displayLink];
  167. });
  168. }
  169. }
  170. - (void)setHighlighted:(BOOL)highlighted
  171. {
  172. if (!self.animatedImage) {
  173. [super setHighlighted:highlighted];
  174. }
  175. }
  176. - (UIImage *)image
  177. {
  178. return self.animatedImage ?: [super image];
  179. }
  180. - (CGSize)sizeThatFits:(CGSize)size
  181. {
  182. return self.image.size;
  183. }
  184. @end