// // RoomHighValueGiftBanner.m // YuMi // // Created by P on 2024/11/1. // #import "RoomHighValueGiftBannerAnimation.h" #import #import "SVGA.h" #import "AttachmentModel.h" #import "GiftReceiveInfoModel.h" #import "XCCurrentVCStackManager.h" #import "XPRoomViewController.h" #import "RoomHostDelegate.h" #import "RoomInfoModel.h" #import "XPSkillCardPlayerManager.h" @interface RoomHighValueGiftBannerAnimation () ///背景 @property (nonatomic,strong) UIImageView *backImageView; @property (nonatomic, strong) SVGAImageView *svgaImageView; ///赠送者头像 @property(nonatomic,strong) NetImageView *senderAvatarView; ///赠送内容,who send who @property(nonatomic,strong) MarqueeLabel *senderScrollLabel; ///房间名称 @property(nonatomic,strong) MarqueeLabel *roomNameScrollLabel; ///礼物 @property (nonatomic,strong) NetImageView *giftImageView; ///礼物内容 @property (nonatomic,strong) UILabel *giftNameLabel; @property (nonatomic,strong) UILabel *giftCountLabel; ///去围观 @property(nonatomic,strong) UIButton *goButton; @property (nonatomic, assign) NSInteger roomUid; @property (nonatomic, copy) NSString *bgSourceName; @property (nonatomic, copy) void(^animationComplete)(void); @end @implementation RoomHighValueGiftBannerAnimation + (void)display:(UIView *)superView with:(AttachmentModel *)attachment complete:(void(^)(void))complete { NSInteger height = kGetScaleWidth(110); NSInteger y = 0; GiftReceiveInfoModel *giftNotifyInfo = [GiftReceiveInfoModel modelWithJSON:attachment.data]; __block RoomHighValueGiftBannerAnimation *banner = [[RoomHighValueGiftBannerAnimation alloc] initWithFrame:CGRectMake(KScreenWidth, y, KScreenWidth, height)]; banner.animationComplete = complete; banner.senderAvatarView.imageUrl = giftNotifyInfo.sendUserAvatar; banner.giftImageView.imageUrl = giftNotifyInfo.giftUrl; banner.roomNameScrollLabel.text = giftNotifyInfo.roomTitle; banner.senderScrollLabel.text = [NSString stringWithFormat:@"%@ %@ %@", giftNotifyInfo.sendUserNick, YMLocalizedString(@"XPSessionFindNewGreetListView3"), giftNotifyInfo.recvUserNick]; banner.giftNameLabel.text = giftNotifyInfo.giftName; banner.giftCountLabel.text = [NSString stringWithFormat:@"x %ld", (long)giftNotifyInfo.giftNum]; banner.roomUid = giftNotifyInfo.roomUid; switch (giftNotifyInfo.bgLevel) { case 1: banner.bgSourceName = @"gift_normal_1"; break; case 2: banner.bgSourceName = @"gift_normal_2"; break; case 3: banner.bgSourceName = @"gift_normal_3"; break; case 4: banner.bgSourceName = @"gift_VIP_1"; break; case 5: banner.bgSourceName = @"gift_VIP_2"; break; case 6: banner.bgSourceName = @"gift_VIP_3"; break; default: banner.bgSourceName = @"gift_normal_1"; break; } [superView addSubview:banner]; @kWeakify(banner); // 使用 POP 动画移动 banner 到目标位置 [banner popEnterAnimation:^(BOOL finished) { @kStrongify(banner); [banner addNotification]; if (finished) { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [banner popLeaveAnimation:^(bool finished) { if (banner.animationComplete) { banner.animationComplete(); } [banner removeNotification]; [banner removeFromSuperview]; }]; }); } }]; } - (void)dealloc { [self.svgaImageView stopAnimation]; } - (void)handleSwipeNotification { [self dismissBanner]; } - (void)handleTapNotification:(NSNotification *)note { NSValue *value = note.userInfo[@"point"]; CGPoint point = [value CGPointValue]; NSLog(@"🔄 RoomHighValueGiftBannerAnimation: 接收到点击点 %@ (bannerContainer坐标系)", NSStringFromCGPoint(point)); // 将 bannerContainer 坐标系中的点转换为 GameUniversalBannerView 坐标系中的点 CGPoint bannerPoint = [self convertPoint:point fromView:self.superview]; NSLog(@"🔄 RoomHighValueGiftBannerAnimation: 转换为 banner 坐标系 %@", NSStringFromCGPoint(bannerPoint)); NSLog(@"%@", CGRectContainsPoint(self.goButton.frame, bannerPoint) ? @"YES" : @"NO"); // 检查点击是否与 go 按钮重合 CGPoint goButtonPoint = [self.goButton convertPoint:bannerPoint fromView:self]; if ([self.goButton pointInside:goButtonPoint withEvent:nil]) { NSLog(@"🎯 RoomHighValueGiftBannerAnimation: tap 点与 go 按钮重合,触发游戏跳转事件"); [self handleTapGo]; } else { CGPoint screenPoint = [self convertPoint:point toView:nil]; // 发送通知给 FunctionContainer 处理,传递屏幕坐标 [[NSNotificationCenter defaultCenter] postNotificationName:@"BannerTapToFunctionContainer" object:nil userInfo:@{@"point": [NSValue valueWithCGPoint:screenPoint]}]; } } - (void)addNotification { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleSwipeNotification) name:@"SwipeOutBanner" object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleTapNotification:) name:@"TapBanner" object:nil]; } - (void)removeNotification { [[NSNotificationCenter defaultCenter] removeObserver:self]; } - (void)dismissBanner { NSLog(@"🚨 RoomHighValueGiftBannerAnimation dismissBanner 被调用"); [self pop_removeAllAnimations]; // 停止所有动画 [self popLeaveAnimation:^(bool finished) { NSLog(@"🚨 RoomHighValueGiftBannerAnimation 动画完成,调用回调"); if (self.animationComplete) { self.animationComplete(); } else { NSLog(@"🚨 警告: animationComplete 回调为空"); } [self removeFromSuperview]; }]; } - (void)popEnterAnimation:(void(^)(BOOL finished))finish { NSInteger height = kGetScaleWidth(110); POPSpringAnimation *enterAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewFrame]; enterAnimation.toValue = [NSValue valueWithCGRect:CGRectMake(0, 0, KScreenWidth, height)]; enterAnimation.springBounciness = 10; // 弹性系数 enterAnimation.springSpeed = 12; // 动画速度 enterAnimation.completionBlock = ^(POPAnimation *anim, BOOL finished) { if (finish) { finish(finished); } }; [self pop_addAnimation:enterAnimation forKey:@"enterAnimation"]; } - (void)popLeaveAnimation:(void(^)(bool finished))finish { NSInteger height = kGetScaleWidth(110); POPBasicAnimation *exitAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPViewFrame]; exitAnimation.toValue = [NSValue valueWithCGRect:CGRectMake(-KScreenWidth, 0, KScreenWidth, height)]; exitAnimation.duration = 0.25; // 动画持续时间 exitAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; exitAnimation.completionBlock = ^(POPAnimation *anim, BOOL finished) { if (finish) { finish(finished); } }; [self pop_addAnimation:exitAnimation forKey:@"exitAnimation"]; } - (void)handleTapGo { // 找到當前房間 UIViewController * controllerView = [XCCurrentVCStackManager shareManager].getCurrentVC; __block XPRoomViewController *roomVC = nil; [controllerView.navigationController.viewControllers enumerateObjectsUsingBlock:^(__kindof UIViewController * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { if ([obj isKindOfClass:[XPRoomViewController class]]) { [controllerView.navigationController popToRootViewControllerAnimated:NO]; roomVC = obj; *stop = YES; } }]; if (roomVC) { // 是否相同房間 if ([roomVC getRoomInfo].uid == self.roomUid) { return; } __block NSString *targetRoomUid = @(self.roomUid).stringValue; [TTPopup alertWithMessage:YMLocalizedString(@"Combo_10") confirmHandler:^{ [roomVC exitRoom]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [XPRoomViewController openRoom:targetRoomUid viewController:[XCCurrentVCStackManager shareManager].getCurrentVC]; }); } cancelHandler:^{}]; } else { [XPRoomViewController openRoom:@(self.roomUid).stringValue viewController:[XCCurrentVCStackManager shareManager].getCurrentVC]; } } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { [self setupUI]; } return self; } - (void)setBgSourceName:(NSString *)bgSourceName { _bgSourceName = bgSourceName; @kWeakify(self); SVGAParser *parser = [[SVGAParser alloc] init]; [parser parseWithNamed:self.bgSourceName inBundle:[NSBundle mainBundle] completionBlock:^(SVGAVideoEntity * _Nonnull videoItem) { @kStrongify(self); self.svgaImageView.videoItem = videoItem; [self.svgaImageView startAnimation]; } failureBlock:^(NSError * _Nonnull error) { @kStrongify(self); if (self.animationComplete) { self.animationComplete(); } }]; } - (void)setupUI { [self addSubview:self.backImageView]; [self.backImageView mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.mas_equalTo(self); }]; [self addSubview:self.svgaImageView]; [self.svgaImageView mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.mas_equalTo(self); }]; [self addSubview:self.senderAvatarView]; [self.senderAvatarView mas_makeConstraints:^(MASConstraintMaker *make) { make.centerY.mas_equalTo(self); make.leading.mas_equalTo(kGetScaleWidth(38)); make.size.mas_equalTo(CGSizeMake(36, 36)); }]; [self addSubview:self.giftImageView]; [self.giftImageView mas_makeConstraints:^(MASConstraintMaker *make) { make.centerY.mas_equalTo(self); make.trailing.mas_equalTo(kGetScaleWidth(-106)); make.size.mas_equalTo(CGSizeMake(46, 46)); }]; [self addSubview:self.senderScrollLabel]; [self.senderScrollLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.top.mas_equalTo(40); make.leading.mas_equalTo(self.senderAvatarView.mas_trailing).offset(4); make.trailing.mas_equalTo(self.giftImageView.mas_leading).offset(-4); make.height.mas_equalTo(16); }]; [self addSubview:self.giftNameLabel]; [self.giftNameLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.top.mas_equalTo(self.senderScrollLabel.mas_bottom).offset(8); make.leading.mas_equalTo(self.senderAvatarView.mas_trailing).offset(4); make.height.mas_equalTo(16); }]; [self addSubview:self.giftCountLabel]; [self.giftCountLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.bottom.mas_equalTo(self.giftNameLabel); make.leading.mas_equalTo(self.giftNameLabel.mas_trailing).offset(7); make.height.mas_equalTo(22); }]; UIImageView *room = [[UIImageView alloc] initWithImage:kImage(@"gift_banner_room")]; [self addSubview:room]; [room mas_makeConstraints:^(MASConstraintMaker *make) { make.leading.mas_equalTo(self.giftImageView.mas_trailing).offset(2); make.top.mas_equalTo(self.giftImageView); make.width.height.mas_equalTo(16); }]; [self addSubview:self.roomNameScrollLabel]; [self.roomNameScrollLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.centerY.mas_equalTo(room); make.leading.mas_equalTo(room.mas_trailing).offset(2); make.trailing.mas_equalTo(self).offset(-34); }]; [self addSubview:self.goButton]; [self.goButton mas_makeConstraints:^(MASConstraintMaker *make) { make.leading.mas_equalTo(self.giftImageView.mas_trailing).offset(8); make.top.mas_equalTo(self.roomNameScrollLabel.mas_bottom).offset(4); make.size.mas_equalTo(CGSizeMake(55, 20)); }]; } #pragma mark - - (UIImageView *)backImageView { if (!_backImageView) { _backImageView = [[UIImageView alloc] init]; } return _backImageView; } - (SVGAImageView *)svgaImageView { if (!_svgaImageView) { _svgaImageView = [[SVGAImageView alloc] init]; _svgaImageView.clearsAfterStop = YES; } return _svgaImageView; } - (NetImageView *)senderAvatarView { if (!_senderAvatarView) { NetImageConfig * config = [[NetImageConfig alloc] init]; config.placeHolder = [UIImageConstant defaultAvatarPlaceholder]; config.imageType = ImageTypeUserIcon; _senderAvatarView = [[NetImageView alloc] initWithConfig:config]; _senderAvatarView.layer.masksToBounds = YES; _senderAvatarView.layer.cornerRadius = 18; _senderAvatarView.contentMode = UIViewContentModeScaleAspectFill; } return _senderAvatarView; } - (MarqueeLabel *)senderScrollLabel{ if(!_senderScrollLabel){ _senderScrollLabel = [[MarqueeLabel alloc] init]; _senderScrollLabel.scrollDuration = 6.0; _senderScrollLabel.textColor = [UIColor whiteColor]; _senderScrollLabel.fadeLength = 8.0f; _senderScrollLabel.font = kFontMedium(11); _senderScrollLabel.textAlignment = NSTextAlignmentLeft; } return _senderScrollLabel; } - (MarqueeLabel *)roomNameScrollLabel{ if(!_roomNameScrollLabel){ _roomNameScrollLabel = [[MarqueeLabel alloc] init]; _roomNameScrollLabel.textColor = [UIColor whiteColor]; _roomNameScrollLabel.scrollDuration = 6.0; _roomNameScrollLabel.fadeLength = 8.0f; _roomNameScrollLabel.font = kFontMedium(11); _roomNameScrollLabel.textAlignment = NSTextAlignmentLeft; } return _roomNameScrollLabel; } - (NetImageView *)giftImageView { if (!_giftImageView) { NetImageConfig * config = [[NetImageConfig alloc] init]; config.placeHolder = [UIImageConstant defaultAvatarPlaceholder]; config.imageType = ImageTypeUserIcon; _giftImageView = [[NetImageView alloc] initWithConfig:config]; _giftImageView.layer.masksToBounds = YES; _giftImageView.layer.cornerRadius = 4; _giftImageView.contentMode = UIViewContentModeScaleAspectFill; } return _giftImageView; } - (UILabel *)giftNameLabel { if (!_giftNameLabel) { _giftNameLabel = [[UILabel alloc] init]; _giftNameLabel.textColor = UIColorFromRGB(0xFFE468); _giftNameLabel.font = kFontMedium(11); } return _giftNameLabel; } - (UILabel *)giftCountLabel { if (!_giftCountLabel) { _giftCountLabel = [[UILabel alloc] init]; _giftCountLabel.textColor = UIColorFromRGB(0xFFE468); _giftCountLabel.font = kFontMedium(17); } return _giftCountLabel; } - (UIButton *)goButton{ if(!_goButton){ _goButton = [UIButton new]; [_goButton setTitle:YMLocalizedString(@"XPAcrossRoomPKPanelView3") forState:UIControlStateNormal]; [_goButton setTitleColor:UIColorFromRGB(0x442a00) forState:UIControlStateNormal]; _goButton.titleLabel.font = kFontRegular(10); _goButton.layer.cornerRadius = kGetScaleWidth(20)/2; _goButton.layer.masksToBounds = YES; // 创建渐变图层 CAGradientLayer *gradientLayer = [CAGradientLayer layer]; gradientLayer.colors = @[(__bridge id)UIColorFromRGB(0xFFFADE).CGColor, (__bridge id)UIColorFromRGB(0xFFE184).CGColor]; gradientLayer.startPoint = CGPointMake(0.0, 0.5); // 顶部中央 gradientLayer.endPoint = CGPointMake(1.0, 0.5); // 底部中央 gradientLayer.frame = CGRectMake(0, 0, 55, 20); // 设置渐变图层大小 // 将渐变图层添加到按钮图层 [_goButton.layer insertSublayer:gradientLayer atIndex:0]; [_goButton addTarget:self action:@selector(handleTapGo) forControlEvents:UIControlEventTouchUpInside]; } return _goButton; } // ========== 事件穿透实现 ========== //- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { // if (!self.userInteractionEnabled || self.hidden || self.alpha <= 0.01) { // return nil; // } // CGPoint goButtonPoint = [self.goButton convertPoint:point fromView:self]; // if ([self.goButton pointInside:goButtonPoint withEvent:event]) { // return self.goButton; // } // // 其他区域返回self,允许触摸事件被父视图的手势识别器处理 // return self; //} @end