// // YMRoomDatingAnimationView.m // YUMI // // Created by YUMI on 2022/1/5. // #import "XPRoomDatingAnimationView.h" ///Third #import #import #import ///Model #import "YUMIMacroUitls.h" #import "DJDKMIMOMColor.h" #import "UIButton+EnlargeTouchArea.h" ///Model #import "DatingInfoModel.h" @interface XPRoomDatingAnimationView () ///背景 @property (nonatomic,strong) UIView *backView; ///动画管理类 @property (strong, nonatomic) SVGAParser *parser; ///播放相亲结果的SVGA @property (nonatomic, strong) SVGAImageView *datingSvgaImageView; ///倒计时的背景 @property (nonatomic,strong) UIView *cutTimeBackView; ///倒计时 @property (nonatomic,strong) UILabel *timeLabel; ///分割线 @property (nonatomic,strong) UIView *lineView; ///关闭的按钮 @property (nonatomic,strong) UIButton *closeButton; ///❤的动画 @property (nonatomic,strong) UIImageView *heartImageView; /// @property (nonatomic,copy) void(^FinishBlock)(BOOL result); /// 定时器 @property (nonatomic,strong) id timer; @end @implementation XPRoomDatingAnimationView - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { [self addSubview:self.backView]; [self addSubview:self.datingSvgaImageView]; [self addSubview:self.cutTimeBackView]; [self addSubview:self.heartImageView]; [self.cutTimeBackView addSubview:self.timeLabel]; [self.cutTimeBackView addSubview:self.lineView]; [self.cutTimeBackView addSubview:self.closeButton]; [self initContrations]; } return self; } #pragma mark - Resonse - (void)closetButtonAction:(UIButton *)sender { if (self.FinishBlock) { [NSObject cancelPreviousPerformRequestsWithTarget:self]; self.FinishBlock(YES); } } #pragma mark - Pirvate Method - (void)initContrations { [self mas_makeConstraints:^(MASConstraintMaker *make) { make.width.mas_equalTo(KScreenWidth); make.height.mas_equalTo(KScreenHeight); }]; [self.backView mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.mas_equalTo(self); }]; [self.datingSvgaImageView mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.mas_equalTo(self); }]; [self.cutTimeBackView mas_makeConstraints:^(MASConstraintMaker *make) { make.size.mas_equalTo(CGSizeMake(70, 25)); make.right.mas_equalTo(self).offset(-12); make.top.mas_equalTo(self).offset(41 + kSafeAreaTopHeight); }]; [self.timeLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.left.mas_equalTo(self.cutTimeBackView).offset(13); make.centerY.mas_equalTo(self.cutTimeBackView); }]; [self.lineView mas_makeConstraints:^(MASConstraintMaker *make) { make.center.mas_equalTo(self.cutTimeBackView); make.size.mas_equalTo(CGSizeMake(0.5, 13)); }]; [self.closeButton mas_makeConstraints:^(MASConstraintMaker *make) { make.size.mas_equalTo(CGSizeMake(14, 14)); make.centerY.mas_equalTo(self.cutTimeBackView); make.left.mas_equalTo(self.lineView.mas_right).offset(8); }]; } - (void)stopAnimation { if (self.FinishBlock) { [NSObject cancelPreviousPerformRequestsWithTarget:self]; self.FinishBlock(YES); } } - (UIImage *)setCornerWithRadius:(CGFloat)radius andSize:(CGSize)size image:(UIImage *)image { //开启图形上下文 UIGraphicsBeginImageContext(size); //绘制圆角矩形 CGRect rect = CGRectMake(0, 0, size.width, size.height); UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rect byRoundingCorners:UIRectCornerAllCorners cornerRadii:CGSizeMake(radius, radius)]; //将Path添加到上下文中 CGContextAddPath(UIGraphicsGetCurrentContext(), path.CGPath); //裁剪上下文 CGContextClip(UIGraphicsGetCurrentContext()); //将图片绘制到上下文中 [image drawInRect:rect]; //设置绘制模式 CGContextDrawPath(UIGraphicsGetCurrentContext(), kCGPathStroke); //获取图片 UIImage *output = UIGraphicsGetImageFromCurrentImageContext(); //关闭上下文 UIGraphicsEndImageContext(); //返回裁剪好的图片 return output; } - (CAAnimationGroup *)createRoomDatingPickAnimatioOriginPoint:(CGPoint)orginPoint destinationPoint:(CGPoint)destinationPoint { ///刚出来的时候 进行慢慢放大的效果 CAKeyframeAnimation * scaleAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"]; scaleAnimation.duration = 0.5; scaleAnimation.repeatCount = 1; scaleAnimation.values = @[@(0),@(0.2),@(0.4), @(0.6), @(0.8), @(0.9), @(1)]; scaleAnimation.calculationMode = kCAAnimationCubic; scaleAnimation.removedOnCompletion = NO; scaleAnimation.fillMode = kCAFillModeForwards; /// CAKeyframeAnimation * transformAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"]; transformAnimation.beginTime = 0.5; transformAnimation.duration = 1; transformAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];; transformAnimation.values = @[[NSValue valueWithCGPoint:orginPoint],[NSValue valueWithCGPoint:destinationPoint]]; transformAnimation.repeatCount = 1; transformAnimation.removedOnCompletion = NO; transformAnimation.fillMode = kCAFillModeForwards; CAKeyframeAnimation * desScaleformAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"]; desScaleformAnimation.beginTime = 1.5; desScaleformAnimation.duration = 0.5; desScaleformAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];; desScaleformAnimation.values = @[@(1), @(1.2), @(1.4), @(1.6)]; desScaleformAnimation.repeatCount = 1; desScaleformAnimation.removedOnCompletion = NO; desScaleformAnimation.fillMode = kCAFillModeForwards; CAKeyframeAnimation * opacityAnimation = [CAKeyframeAnimation animationWithKeyPath:@"opacity"]; opacityAnimation.beginTime = 1.5; opacityAnimation.duration = 0.5; opacityAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];; opacityAnimation.values = @[@(1),@(0.8),@(0.6),@(0)]; opacityAnimation.repeatCount = 1; opacityAnimation.removedOnCompletion = NO; opacityAnimation.fillMode = kCAFillModeForwards; CAAnimationGroup * group = [CAAnimationGroup animation]; group.animations = @[scaleAnimation, transformAnimation, desScaleformAnimation, opacityAnimation]; group.duration = 2; group.removedOnCompletion = NO; group.fillMode = kCAFillModeForwards; return group;; } - (void)startBeginCutCountWithTotalTime:(int)time { __block int totalTime = time; dispatch_source_t times = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0)); _timer = times; dispatch_source_set_timer(times, DISPATCH_TIME_NOW, 1* NSEC_PER_SEC, 0 * NSEC_PER_SEC); dispatch_source_set_event_handler(times, ^{ dispatch_async(dispatch_get_main_queue(), ^{ if (totalTime <= 5 && totalTime >= 0) { ///开始显示倒计时 self.cutTimeBackView.hidden = NO; self.timeLabel.text = [NSString stringWithFormat:@"%ds", totalTime]; } if (totalTime <= 0) { dispatch_source_cancel(times); self.cutTimeBackView.hidden = YES; } totalTime--; }); }); dispatch_resume(times); } - (void)startPickHeartPersonAnimationOriginPoint:(CGPoint)originPoint targetPoint:(CGPoint)targetPoint { if (originPoint.x > 0 && targetPoint.x > 0) { self.heartImageView.frame = CGRectMake(0, 0, 55, 55); self.heartImageView.hidden = YES; self.backView.hidden = YES; self.heartImageView.hidden = NO; self.heartImageView.center = originPoint; CAAnimationGroup * group = [self createRoomDatingPickAnimatioOriginPoint:originPoint destinationPoint:targetPoint]; [self.heartImageView.layer addAnimation:group forKey:nil]; [self performSelector:@selector(aniationDidFinish:) withObject:self.heartImageView afterDelay:(2)]; } } - (void)aniationDidFinish:(UIImageView *)giftImageView{ [giftImageView.layer removeAllAnimations]; giftImageView.hidden = YES; } #pragma mark - Public Method - (void)startAnimationWithModel:(DatingInfoModel *)model finishBlock:(void (^)(BOOL))finishBlock { self.FinishBlock = finishBlock; if (model.hasHeart) { if (model.svgaUrl) { [self startPalySVGAWithUrl:model]; } else { ///如果是心动选人的话 但是没有SVGA的话 直接结束 ///播完之后直接结束这次 if (self.FinishBlock) { self.FinishBlock(YES); } } } else { ///不是心动选人的话 那就不用播两次 爱心的动画 [self startPickHeartPersonAnimationOriginPoint:model.originPoint targetPoint:model.targetPoint]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ ///心动结束了 直接结束此次 if (self.FinishBlock) { self.FinishBlock(YES); } }); } } ///播放SVGA的时候 需要先播放选人的动画 - (void)startPalySVGAWithUrl:(DatingInfoModel *)model { if (model.svgaUrl) { self.backView.hidden = NO; [[SDWebImageManager sharedManager] loadImageWithURL:[NSURL URLWithString:model.avatar] options:SDWebImageRetryFailed progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { if (image) { image = [self setCornerWithRadius:200 andSize:CGSizeMake(400, 400) image:image]; [self.datingSvgaImageView setImage:image forKey:@"z_tx"]; } }]; NSString * title = model.nickname ? model.nickname : @""; if (title.length >= 5) { title = [NSString stringWithFormat:@"%@…", [title substringToIndex:5]]; } NSMutableAttributedString * rightAttribut = [[NSMutableAttributedString alloc] initWithString:title]; [rightAttribut addAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:28], NSForegroundColorAttributeName:[UIColor whiteColor]} range:NSMakeRange(0, title.length)]; [self.datingSvgaImageView setAttributedText:rightAttribut forKey:@"z_yhname"]; [[SDWebImageManager sharedManager] loadImageWithURL:[NSURL URLWithString:model.targetAvatar] options:SDWebImageRetryFailed progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { if (image) { image = [self setCornerWithRadius:200 andSize:CGSizeMake(400, 400) image:image]; [self.datingSvgaImageView setImage:image forKey:@"y_tx"]; } }]; NSString * leftTitle = model.targetNickname ? model.targetNickname : @""; if (leftTitle.length >= 5) { leftTitle = [NSString stringWithFormat:@"%@…", [leftTitle substringToIndex:5]]; } NSMutableAttributedString * leftAttribut = [[NSMutableAttributedString alloc] initWithString:leftTitle]; [leftAttribut addAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:28], NSForegroundColorAttributeName:[UIColor whiteColor]} range:NSMakeRange(0, leftTitle.length)]; [self.datingSvgaImageView setAttributedText:leftAttribut forKey:@"y_yhname"]; @kWeakify(self); [self.parser parseWithURL:[NSURL URLWithString:model.svgaUrl] completionBlock:^(SVGAVideoEntity * _Nonnull videoItem) { @kStrongify(self); self.datingSvgaImageView.hidden = NO; self.datingSvgaImageView.videoItem = videoItem; self.datingSvgaImageView.loops = 1; self.datingSvgaImageView.alpha = 1; self.datingSvgaImageView.clearsAfterStop = YES; [ self.datingSvgaImageView startAnimation]; [self startBeginCutCountWithTotalTime:model.svgaSecond]; } failureBlock:^(NSError * _Nonnull error) { }]; [self performSelector:@selector(stopAnimation) withObject:nil afterDelay:model.svgaSecond]; } } - (UIImageView *)heartImageView { if (!_heartImageView) { _heartImageView = [[UIImageView alloc] init]; _heartImageView.image = [UIImage imageNamed:@"room_mode_dating_pick_heart"]; _heartImageView.hidden = YES; } return _heartImageView; } - (UIView *)backView { if (!_backView) { _backView = [[UIView alloc] init]; _backView.backgroundColor = UIColorRGBAlpha(0x000000, 0.3); _backView.hidden = YES; } return _backView; } - (UILabel *)timeLabel { if (!_timeLabel) { _timeLabel = [[UILabel alloc] init]; _timeLabel.text = @"5S"; _timeLabel.font = [UIFont systemFontOfSize:15]; _timeLabel.textColor = UIColorFromRGB(0xFFFEFE); } return _timeLabel; } - (UIView *)cutTimeBackView { if (!_cutTimeBackView) { _cutTimeBackView = [[UIView alloc] init]; _cutTimeBackView.backgroundColor = UIColorRGBAlpha(0x000000, 0.3); _cutTimeBackView.layer.masksToBounds = YES; _cutTimeBackView.layer.cornerRadius = 25/2; _cutTimeBackView.hidden = YES; } return _cutTimeBackView; } - (UIButton *)closeButton { if (!_closeButton) { _closeButton = [UIButton buttonWithType: UIButtonTypeCustom]; [_closeButton setImage:[UIImage imageNamed:@"common_close_white"] forState:UIControlStateNormal]; [_closeButton addTarget:self action:@selector(closetButtonAction:) forControlEvents:UIControlEventTouchUpInside]; [_closeButton setEnlargeEdgeWithTop:10 right:10 bottom:10 left:10]; } return _closeButton; } - (UIView *)lineView { if (!_lineView) { _lineView = [[UIView alloc] init]; _lineView.backgroundColor = UIColor.whiteColor; } return _lineView; } - (SVGAParser *)parser { if (!_parser) { _parser = [[SVGAParser alloc]init]; } return _parser; } - (SVGAImageView *)datingSvgaImageView { if (!_datingSvgaImageView) { _datingSvgaImageView = [[SVGAImageView alloc]init]; _datingSvgaImageView.backgroundColor = [UIColor clearColor]; _datingSvgaImageView.frame = self.bounds; _datingSvgaImageView.userInteractionEnabled = YES; } return _datingSvgaImageView; } @end