// // XYExpressionItemView.m // Starbuds // // Created by gy on 2020/8/24. // Copyright © 2020 翟玉磊. All rights reserved. // #import "XYExpressionItemView.h" #import #import #import #import "XYResourceCacheManager.h" @interface XYExpressionItemView() @property (nonatomic, strong) SVGAPlayer *expressionPlayer; @property (nonatomic, strong) UIImageView *imageView; @property (nonatomic, strong) FLAnimatedImageView *gifImageView; @property (nonatomic, strong) YYAnimatedImageView *yyImageView; @property (nonatomic, assign) NSInteger animatedImgCount; @property (nonatomic, copy) NSString *expressionId; @property (nonatomic, copy) NSString *expressionUrl; /// 播放次数 @property (nonatomic, assign) NSInteger playTimes; /// 停留帧数 @property (nonatomic, assign) NSInteger finalFrame; /// 播放类型 @property (nonatomic, assign) XYExpressionType expressionType; @property (nonatomic, strong) NSTimer *timer; @end @implementation XYExpressionItemView #pragma mark - Public - (void)reload:(XYLiveRoomMessageInfo *)info{ self.backgroundColor = [UIColor clearColor]; [self playExpression:info.expUrl expressionId:info.expId playTimes:info.playTimes finalFrame:info.finalFrame]; } - (void)playExpression:(NSString *)expUrl expressionId:(NSString *)expressionId playTimes:(NSInteger)playTimes finalFrame:(NSInteger)finalFrame { if (StringIsEmpty(expUrl)) { return; } // 重置状态 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(resetState) object:nil]; [self resetState]; self.expressionId = expressionId; self.expressionUrl = expUrl; self.finalFrame = finalFrame; self.playTimes = playTimes; XYExpressionType expressionType = [XYExpressionItemView expressionTypeWithURL:expUrl]; switch (expressionType) { case XYExpressionTypeSVGA: [self playSVGAExpression]; break; case XYExpressionTypeGIF: [self playGIFExpression]; break; default: [self playPNGExpression]; break; } } - (void)stopAnimating { if (_yyImageView) { [_yyImageView stopAnimating]; } if (_gifImageView) { [_gifImageView stopAnimating]; } } - (void)clear { if (_timer) { [_timer invalidate]; _timer = nil; } if (_imageView) { [_imageView removeFromSuperview]; _imageView = nil; } if (_expressionPlayer) { [_expressionPlayer clear]; [_expressionPlayer removeFromSuperview]; _expressionPlayer = nil; } if (_gifImageView) { [_gifImageView stopAnimating]; [_gifImageView removeFromSuperview]; _gifImageView = nil; } if (_yyImageView) { [_yyImageView removeObserver:self forKeyPath:@"currentAnimatedImageIndex"]; [_yyImageView stopAnimating]; _yyImageView.image = nil; [_yyImageView removeFromSuperview]; _yyImageView = nil; } } #pragma mark - Method - (void)playSVGAExpression { // 播放svga [[SVGAParser new] parseWithURL:UrlForString(self.expressionUrl) completionBlock:^(SVGAVideoEntity * _Nullable videoItem) { self.expressionPlayer.videoItem = videoItem; self.expressionPlayer.loops = (int)self.playTimes; [self.expressionPlayer startAnimation]; } failureBlock:^(NSError * _Nullable error) { }]; } - (void)playGIFExpression { NSData *gifData = [[XYResourceCacheManager sharedInstance] getResourceWithType:XYResourceTypeExpression URLStr:self.expressionUrl resource:self.expressionId]; if (gifData) { FLAnimatedImage *image = [FLAnimatedImage animatedImageWithGIFData:gifData]; if (image) { self.gifImageView.animatedImage = image; } }else { [[XYResourceCacheManager sharedInstance] downloadResourceWithURLStr:self.expressionUrl resourceId:self.expressionId resourceType:XYResourceTypeExpression completeBlock:^(NSString * _Nonnull resourcePath) { if (StringIsNotEmpty(resourcePath)) { NSData *gifData = [[XYResourceCacheManager sharedInstance] getResourceWithType:XYResourceTypeExpression URLStr:self.expressionUrl resource:self.expressionId]; FLAnimatedImage *image = [FLAnimatedImage animatedImageWithGIFData:gifData]; if (image) { self.gifImageView.animatedImage = image; } } }]; } } - (void)playPNGExpression { NSData *imageData = [[XYResourceCacheManager sharedInstance] getResourceWithType:XYResourceTypeExpression URLStr:self.expressionUrl resource:self.expressionId]; if (imageData) { YYImage *image = [YYImage imageWithData:imageData]; // yyImageView就是YYAnimatedImageView [self.yyImageView addObserver:self forKeyPath:@"currentAnimatedImageIndex" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil]; // animatedImgCount记录gif动图内图片的数量 if ([image respondsToSelector:@selector(animatedImageFrameCount)]) { self.animatedImgCount = [image animatedImageFrameCount]; } self.yyImageView.image = image; }else { [[XYResourceCacheManager sharedInstance] downloadResourceWithURLStr:self.expressionUrl resourceId:self.expressionId resourceType:XYResourceTypeExpression completeBlock:^(NSString * _Nonnull resourcePath) { if (StringIsNotEmpty(resourcePath)) { NSData *imageData = [[XYResourceCacheManager sharedInstance] getResourceWithType:XYResourceTypeExpression URLStr:self.expressionUrl resource:self.expressionId]; // yyImageView就是YYAnimatedImageView [self.yyImageView addObserver:self forKeyPath:@"currentAnimatedImageIndex" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil]; YYImage *image = [YYImage imageWithData:imageData]; // animatedImgCount记录gif动图内图片的数量 if ([image respondsToSelector:@selector(animatedImageFrameCount)]) { self.animatedImgCount = [image animatedImageFrameCount]; } self.yyImageView.image = image; } }]; } } // KVO监听回调 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if ([keyPath isEqualToString:@"currentAnimatedImageIndex"]) { if ([change[NSKeyValueChangeNewKey] respondsToSelector:@selector(integerValue)]) { NSInteger currentAnimatedImageIndex = [change[NSKeyValueChangeNewKey] integerValue]; if (self.animatedImgCount > 0) { if (currentAnimatedImageIndex == self.animatedImgCount - 1) { self.playTimes--; if (self.playTimes == 0) { // 动画结束 dispatch_async(dispatch_get_main_queue(), ^{ [self.yyImageView stopAnimating]; if (self.clearsAfterStop) { [self resetState]; } }); } } } else { [self.yyImageView stopAnimating]; if (self.clearsAfterStop) { [self resetState]; } } } } } + (XYExpressionType)expressionTypeWithURL:(NSString *)expURL { NSString *temp = [expURL pathExtension]; if ([temp isEqualToString:@"svga"]) { return XYExpressionTypeSVGA; } if ([temp isEqualToString:@"gif"]) { return XYExpressionTypeGIF; } return XYExpressionTypePNG; } #pragma mark — SVGAPlayerDelegate /// 播放完成 - (void)svgaPlayerDidFinishedAnimation:(SVGAPlayer *)player { if (player.tag == 1) { if (self.finalFrame > 0) { [self.expressionPlayer stepToFrame:self.finalFrame andPlay:NO]; }else{ //gy todo [self.expressionPlayer stepToPercentage:0.9 andPlay:NO]; } if (self.clearsAfterStop) { [self hideExpression]; } } } - (void)hideExpression { [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(resetState) object:nil]; [self performSelector:@selector(resetState) withObject:nil afterDelay:0.5]; } - (void)resetState { self.expressionId = @""; self.expressionUrl = @""; self.finalFrame = 0; self.playTimes = 1; self.animatedImgCount = 0; [self clear]; } - (SVGAPlayer *)expressionPlayer { if (!_expressionPlayer) { _expressionPlayer = [[SVGAPlayer alloc] init]; _expressionPlayer.delegate = self; _expressionPlayer.loops = 1; _expressionPlayer.clearsAfterStop = YES; _expressionPlayer.tag = 1; _expressionPlayer.clipsToBounds = YES; _expressionPlayer.frame = self.bounds; [self addSubview:_expressionPlayer]; if (_expressionPlayer.f_heigh == 0 || _expressionPlayer.f_width == 0) { [_expressionPlayer mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self); }]; } } return _expressionPlayer; } - (UIImageView *)imageView{ if (_imageView == nil) { _imageView = [[UIImageView alloc] init]; _imageView.contentMode = UIViewContentModeScaleAspectFill; _imageView.clipsToBounds = YES; _imageView.frame = self.bounds; [self addSubview:_imageView]; if (_imageView.f_heigh == 0 || _imageView.f_width == 0) { [_imageView mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self); }]; } } return _imageView; } - (FLAnimatedImageView *)gifImageView { if (_gifImageView == nil) { _gifImageView = [[FLAnimatedImageView alloc] init]; _gifImageView.contentMode = UIViewContentModeScaleAspectFill; _gifImageView.clipsToBounds = YES; _gifImageView.frame = self.bounds; _gifImageView.runLoopMode = NSDefaultRunLoopMode; [self addSubview:_gifImageView]; if (_gifImageView.f_heigh == 0 || _gifImageView.f_width == 0) { [_gifImageView mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self); }]; } WeakSelf [_gifImageView setLoopCompletionBlock:^(NSUInteger loopCountRemaining) { weakSelf.playTimes--; if (weakSelf.playTimes == 0) { [weakSelf.gifImageView stopAnimating]; if (weakSelf.clearsAfterStop) { [weakSelf hideExpression]; } } }]; } return _gifImageView; } - (YYAnimatedImageView *)yyImageView { if (_yyImageView == nil) { _yyImageView = [[YYAnimatedImageView alloc] init]; _yyImageView.contentMode = UIViewContentModeScaleAspectFill; _yyImageView.clipsToBounds = YES; _yyImageView.frame = self.bounds; _yyImageView.runloopMode = NSDefaultRunLoopMode; [self addSubview:_yyImageView]; if (_yyImageView.f_heigh == 0 || _yyImageView.f_width == 0) { [_yyImageView mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self); }]; } } return _yyImageView; } /* // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { // Drawing code } */ @end