XYExpressionItemView.m 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. //
  2. // XYExpressionItemView.m
  3. // Starbuds
  4. //
  5. // Created by gy on 2020/8/24.
  6. // Copyright © 2020 翟玉磊. All rights reserved.
  7. //
  8. #import "XYExpressionItemView.h"
  9. #import <SVGAPlayer/SVGA.h>
  10. #import <FLAnimatedImage/FLAnimatedImage.h>
  11. #import <YYImage/YYImage.h>
  12. #import "XYResourceCacheManager.h"
  13. @interface XYExpressionItemView()<SVGAPlayerDelegate>
  14. @property (nonatomic, strong) SVGAPlayer *expressionPlayer;
  15. @property (nonatomic, strong) UIImageView *imageView;
  16. @property (nonatomic, strong) FLAnimatedImageView *gifImageView;
  17. @property (nonatomic, strong) YYAnimatedImageView *yyImageView;
  18. @property (nonatomic, assign) NSInteger animatedImgCount;
  19. @property (nonatomic, copy) NSString *expressionId;
  20. @property (nonatomic, copy) NSString *expressionUrl;
  21. /// 播放次数
  22. @property (nonatomic, assign) NSInteger playTimes;
  23. /// 停留帧数
  24. @property (nonatomic, assign) NSInteger finalFrame;
  25. /// 播放类型
  26. @property (nonatomic, assign) XYExpressionType expressionType;
  27. @property (nonatomic, strong) NSTimer *timer;
  28. @end
  29. @implementation XYExpressionItemView
  30. #pragma mark - Public
  31. - (void)reload:(XYLiveRoomMessageInfo *)info{
  32. self.backgroundColor = [UIColor clearColor];
  33. [self playExpression:info.expUrl expressionId:info.expId playTimes:info.playTimes finalFrame:info.finalFrame];
  34. }
  35. - (void)playExpression:(NSString *)expUrl expressionId:(NSString *)expressionId playTimes:(NSInteger)playTimes finalFrame:(NSInteger)finalFrame {
  36. if (StringIsEmpty(expUrl)) {
  37. return;
  38. }
  39. // 重置状态
  40. [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(resetState) object:nil];
  41. [self resetState];
  42. self.expressionId = expressionId;
  43. self.expressionUrl = expUrl;
  44. self.finalFrame = finalFrame;
  45. self.playTimes = playTimes;
  46. XYExpressionType expressionType = [XYExpressionItemView expressionTypeWithURL:expUrl];
  47. switch (expressionType) {
  48. case XYExpressionTypeSVGA:
  49. [self playSVGAExpression];
  50. break;
  51. case XYExpressionTypeGIF:
  52. [self playGIFExpression];
  53. break;
  54. default:
  55. [self playPNGExpression];
  56. break;
  57. }
  58. }
  59. - (void)stopAnimating {
  60. if (_yyImageView) {
  61. [_yyImageView stopAnimating];
  62. }
  63. if (_gifImageView) {
  64. [_gifImageView stopAnimating];
  65. }
  66. }
  67. - (void)clear {
  68. if (_timer) {
  69. [_timer invalidate];
  70. _timer = nil;
  71. }
  72. if (_imageView) {
  73. [_imageView removeFromSuperview];
  74. _imageView = nil;
  75. }
  76. if (_expressionPlayer) {
  77. [_expressionPlayer clear];
  78. [_expressionPlayer removeFromSuperview];
  79. _expressionPlayer = nil;
  80. }
  81. if (_gifImageView) {
  82. [_gifImageView stopAnimating];
  83. [_gifImageView removeFromSuperview];
  84. _gifImageView = nil;
  85. }
  86. if (_yyImageView) {
  87. [_yyImageView removeObserver:self forKeyPath:@"currentAnimatedImageIndex"];
  88. [_yyImageView stopAnimating];
  89. _yyImageView.image = nil;
  90. [_yyImageView removeFromSuperview];
  91. _yyImageView = nil;
  92. }
  93. }
  94. #pragma mark - Method
  95. - (void)playSVGAExpression {
  96. // 播放svga
  97. [[SVGAParser new] parseWithURL:UrlForString(self.expressionUrl) completionBlock:^(SVGAVideoEntity * _Nullable videoItem) {
  98. self.expressionPlayer.videoItem = videoItem;
  99. self.expressionPlayer.loops = (int)self.playTimes;
  100. [self.expressionPlayer startAnimation];
  101. } failureBlock:^(NSError * _Nullable error) {
  102. }];
  103. }
  104. - (void)playGIFExpression {
  105. NSData *gifData = [[XYResourceCacheManager sharedInstance] getResourceWithType:XYResourceTypeExpression URLStr:self.expressionUrl resource:self.expressionId];
  106. if (gifData) {
  107. FLAnimatedImage *image = [FLAnimatedImage animatedImageWithGIFData:gifData];
  108. if (image) {
  109. self.gifImageView.animatedImage = image;
  110. }
  111. }else {
  112. [[XYResourceCacheManager sharedInstance] downloadResourceWithURLStr:self.expressionUrl resourceId:self.expressionId resourceType:XYResourceTypeExpression completeBlock:^(NSString * _Nonnull resourcePath) {
  113. if (StringIsNotEmpty(resourcePath)) {
  114. NSData *gifData = [[XYResourceCacheManager sharedInstance] getResourceWithType:XYResourceTypeExpression URLStr:self.expressionUrl resource:self.expressionId];
  115. FLAnimatedImage *image = [FLAnimatedImage animatedImageWithGIFData:gifData];
  116. if (image) {
  117. self.gifImageView.animatedImage = image;
  118. }
  119. }
  120. }];
  121. }
  122. }
  123. - (void)playPNGExpression {
  124. NSData *imageData = [[XYResourceCacheManager sharedInstance] getResourceWithType:XYResourceTypeExpression URLStr:self.expressionUrl resource:self.expressionId];
  125. if (imageData) {
  126. YYImage *image = [YYImage imageWithData:imageData];
  127. // yyImageView就是YYAnimatedImageView
  128. [self.yyImageView addObserver:self forKeyPath:@"currentAnimatedImageIndex" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];
  129. // animatedImgCount记录gif动图内图片的数量
  130. if ([image respondsToSelector:@selector(animatedImageFrameCount)]) {
  131. self.animatedImgCount = [image animatedImageFrameCount];
  132. }
  133. self.yyImageView.image = image;
  134. }else {
  135. [[XYResourceCacheManager sharedInstance] downloadResourceWithURLStr:self.expressionUrl resourceId:self.expressionId resourceType:XYResourceTypeExpression completeBlock:^(NSString * _Nonnull resourcePath) {
  136. if (StringIsNotEmpty(resourcePath)) {
  137. NSData *imageData = [[XYResourceCacheManager sharedInstance] getResourceWithType:XYResourceTypeExpression URLStr:self.expressionUrl resource:self.expressionId];
  138. // yyImageView就是YYAnimatedImageView
  139. [self.yyImageView addObserver:self forKeyPath:@"currentAnimatedImageIndex" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];
  140. YYImage *image = [YYImage imageWithData:imageData];
  141. // animatedImgCount记录gif动图内图片的数量
  142. if ([image respondsToSelector:@selector(animatedImageFrameCount)]) {
  143. self.animatedImgCount = [image animatedImageFrameCount];
  144. }
  145. self.yyImageView.image = image;
  146. }
  147. }];
  148. }
  149. }
  150. // KVO监听回调
  151. - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
  152. if ([keyPath isEqualToString:@"currentAnimatedImageIndex"]) {
  153. if ([change[NSKeyValueChangeNewKey] respondsToSelector:@selector(integerValue)]) {
  154. NSInteger currentAnimatedImageIndex = [change[NSKeyValueChangeNewKey] integerValue];
  155. if (self.animatedImgCount > 0) {
  156. if (currentAnimatedImageIndex == self.animatedImgCount - 1) {
  157. self.playTimes--;
  158. if (self.playTimes == 0) {
  159. // 动画结束
  160. dispatch_async(dispatch_get_main_queue(), ^{
  161. [self.yyImageView stopAnimating];
  162. if (self.clearsAfterStop) {
  163. [self resetState];
  164. }
  165. });
  166. }
  167. }
  168. }
  169. else {
  170. [self.yyImageView stopAnimating];
  171. if (self.clearsAfterStop) {
  172. [self resetState];
  173. }
  174. }
  175. }
  176. }
  177. }
  178. + (XYExpressionType)expressionTypeWithURL:(NSString *)expURL {
  179. NSString *temp = [expURL pathExtension];
  180. if ([temp isEqualToString:@"svga"]) {
  181. return XYExpressionTypeSVGA;
  182. }
  183. if ([temp isEqualToString:@"gif"]) {
  184. return XYExpressionTypeGIF;
  185. }
  186. return XYExpressionTypePNG;
  187. }
  188. #pragma mark — SVGAPlayerDelegate
  189. /// 播放完成
  190. - (void)svgaPlayerDidFinishedAnimation:(SVGAPlayer *)player {
  191. if (player.tag == 1) {
  192. if (self.finalFrame > 0) {
  193. [self.expressionPlayer stepToFrame:self.finalFrame andPlay:NO];
  194. }else{
  195. //gy todo
  196. [self.expressionPlayer stepToPercentage:0.9 andPlay:NO];
  197. }
  198. if (self.clearsAfterStop) {
  199. [self hideExpression];
  200. }
  201. }
  202. }
  203. - (void)hideExpression {
  204. [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(resetState) object:nil];
  205. [self performSelector:@selector(resetState) withObject:nil afterDelay:0.5];
  206. }
  207. - (void)resetState {
  208. self.expressionId = @"";
  209. self.expressionUrl = @"";
  210. self.finalFrame = 0;
  211. self.playTimes = 1;
  212. self.animatedImgCount = 0;
  213. [self clear];
  214. }
  215. - (SVGAPlayer *)expressionPlayer {
  216. if (!_expressionPlayer) {
  217. _expressionPlayer = [[SVGAPlayer alloc] init];
  218. _expressionPlayer.delegate = self;
  219. _expressionPlayer.loops = 1;
  220. _expressionPlayer.clearsAfterStop = YES;
  221. _expressionPlayer.tag = 1;
  222. _expressionPlayer.clipsToBounds = YES;
  223. _expressionPlayer.frame = self.bounds;
  224. [self addSubview:_expressionPlayer];
  225. if (_expressionPlayer.f_heigh == 0 || _expressionPlayer.f_width == 0) {
  226. [_expressionPlayer mas_makeConstraints:^(MASConstraintMaker *make) {
  227. make.edges.equalTo(self);
  228. }];
  229. }
  230. }
  231. return _expressionPlayer;
  232. }
  233. - (UIImageView *)imageView{
  234. if (_imageView == nil) {
  235. _imageView = [[UIImageView alloc] init];
  236. _imageView.contentMode = UIViewContentModeScaleAspectFill;
  237. _imageView.clipsToBounds = YES;
  238. _imageView.frame = self.bounds;
  239. [self addSubview:_imageView];
  240. if (_imageView.f_heigh == 0 || _imageView.f_width == 0) {
  241. [_imageView mas_makeConstraints:^(MASConstraintMaker *make) {
  242. make.edges.equalTo(self);
  243. }];
  244. }
  245. }
  246. return _imageView;
  247. }
  248. - (FLAnimatedImageView *)gifImageView {
  249. if (_gifImageView == nil) {
  250. _gifImageView = [[FLAnimatedImageView alloc] init];
  251. _gifImageView.contentMode = UIViewContentModeScaleAspectFill;
  252. _gifImageView.clipsToBounds = YES;
  253. _gifImageView.frame = self.bounds;
  254. _gifImageView.runLoopMode = NSDefaultRunLoopMode;
  255. [self addSubview:_gifImageView];
  256. if (_gifImageView.f_heigh == 0 || _gifImageView.f_width == 0) {
  257. [_gifImageView mas_makeConstraints:^(MASConstraintMaker *make) {
  258. make.edges.equalTo(self);
  259. }];
  260. }
  261. WeakSelf
  262. [_gifImageView setLoopCompletionBlock:^(NSUInteger loopCountRemaining) {
  263. weakSelf.playTimes--;
  264. if (weakSelf.playTimes == 0) {
  265. [weakSelf.gifImageView stopAnimating];
  266. if (weakSelf.clearsAfterStop) {
  267. [weakSelf hideExpression];
  268. }
  269. }
  270. }];
  271. }
  272. return _gifImageView;
  273. }
  274. - (YYAnimatedImageView *)yyImageView {
  275. if (_yyImageView == nil) {
  276. _yyImageView = [[YYAnimatedImageView alloc] init];
  277. _yyImageView.contentMode = UIViewContentModeScaleAspectFill;
  278. _yyImageView.clipsToBounds = YES;
  279. _yyImageView.frame = self.bounds;
  280. _yyImageView.runloopMode = NSDefaultRunLoopMode;
  281. [self addSubview:_yyImageView];
  282. if (_yyImageView.f_heigh == 0 || _yyImageView.f_width == 0) {
  283. [_yyImageView mas_makeConstraints:^(MASConstraintMaker *make) {
  284. make.edges.equalTo(self);
  285. }];
  286. }
  287. }
  288. return _yyImageView;
  289. }
  290. /*
  291. // Only override drawRect: if you perform custom drawing.
  292. // An empty implementation adversely affects performance during animation.
  293. - (void)drawRect:(CGRect)rect {
  294. // Drawing code
  295. }
  296. */
  297. @end