From 3f97b0293e1b87384c9635a162de44f91eab8867 Mon Sep 17 00:00:00 2001 From: edwinQQQ Date: Fri, 15 Aug 2025 19:34:25 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20Banner=20=E6=89=8B?= =?UTF-8?q?=E5=8A=BF=E4=BC=98=E5=8C=96=E5=AE=9E=E6=96=BD=E6=80=BB=E7=BB=93?= =?UTF-8?q?=E6=96=87=E6=A1=A3=EF=BC=8C=E8=AE=B0=E5=BD=95=E4=BA=86=E5=9C=A8?= =?UTF-8?q?=20RoomAnimationView=20=E4=B8=AD=E5=AF=B9=20banner=20=E6=89=8B?= =?UTF-8?q?=E5=8A=BF=E7=B3=BB=E7=BB=9F=E7=9A=84=E4=BC=98=E5=8C=96=E8=BF=87?= =?UTF-8?q?=E7=A8=8B=EF=BC=8C=E5=8C=85=E6=8B=AC=E6=89=8B=E5=8A=BF=E8=AF=86?= =?UTF-8?q?=E5=88=AB=E5=99=A8=E7=9A=84=E9=87=8D=E6=96=B0=E8=AE=BE=E8=AE=A1?= =?UTF-8?q?=E3=80=81=E5=8C=BA=E5=9F=9F=E5=88=92=E5=88=86=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E3=80=81tap=20=E6=89=8B=E5=8A=BF=E5=A4=84=E7=90=86=E9=80=BB?= =?UTF-8?q?=E8=BE=91=E5=8F=8A=E4=BA=A4=E4=BA=92=E5=8C=BA=E5=9F=9F=E6=A3=80?= =?UTF-8?q?=E6=9F=A5=E7=AD=89=E3=80=82=E5=90=8C=E6=97=B6=EF=BC=8C=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E4=BA=86=E5=A4=9A=E4=B8=AA=E8=A7=86=E5=9B=BE=E4=B8=AD?= =?UTF-8?q?=E7=9A=84=E9=80=9A=E7=9F=A5=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E7=A1=AE=E4=BF=9D=E6=89=8B=E5=8A=BF=E4=BA=8B=E4=BB=B6?= =?UTF-8?q?=E7=9A=84=E5=87=86=E7=A1=AE=E4=BC=A0=E9=80=92=E4=B8=8E=E5=A4=84?= =?UTF-8?q?=E7=90=86=EF=BC=8C=E6=8F=90=E5=8D=87=E7=94=A8=E6=88=B7=E4=BA=A4?= =?UTF-8?q?=E4=BA=92=E4=BD=93=E9=AA=8C=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Banner手势优化实施总结.md | 248 ++++ .../YMMine/View/SubViews/CPGiftBanner.m | 47 +- .../YMNewHome/View/XPNewHomeViewController.m | 19 +- .../AnimationView/GameUniversalBannerView.m | 80 +- .../LuckyGiftWinningBannerView.m | 69 +- .../View/AnimationView/RoomAnimationView.m | 1028 ++++------------- .../RoomHighValueGiftBannerAnimation.m | 65 +- .../AnimationView/XPRoomAnimationHitView.m | 18 +- .../XPRoomFunctionContainerView.m | 85 +- .../YMRoom/View/Common/BravoGiftBannerView.m | 65 +- .../LuckyPackage/LuckyPackageBannerView.m | 57 +- 11 files changed, 871 insertions(+), 910 deletions(-) create mode 100644 Banner手势优化实施总结.md diff --git a/Banner手势优化实施总结.md b/Banner手势优化实施总结.md new file mode 100644 index 00000000..793b5160 --- /dev/null +++ b/Banner手势优化实施总结.md @@ -0,0 +1,248 @@ +# Banner手势优化实施总结 + +## 概述 +本文档记录了在 `RoomAnimationView.m` 中对 banner 手势系统的优化实施过程。 + +## 最新优化内容(2025年1月) + +### 需求描述 +1. **bannerContainer 手势范围调整**: + - 中央宽度 2/3 的位置:保留 swipe 手势 + - 左右两侧各 1/6 宽度:添加 tap 手势 + +2. **tap 手势处理逻辑**: + - 检查当前显示的 banner 是否在 tap 位置可以响应事件 + - 如果可以响应:不处理,让 banner 继续原有逻辑 + - 如果不能响应:保存 tap 位置点,供后续使用 + +### 实施方案 + +#### 1. 手势识别器重新设计 +```objc +- (void)addBnnerContainGesture { + // 创建独立的手势容器,避免与XPRoomAnimationHitView的hitTest冲突 + [self insertSubview:self.bannerSwipeGestureContainer aboveSubview:self.bannerContainer]; + [self insertSubview:self.bannerLeftTapGestureContainer aboveSubview:self.bannerContainer]; + [self insertSubview:self.bannerRightTapGestureContainer aboveSubview:self.bannerContainer]; + + // 设置手势容器的布局约束 + [self.bannerSwipeGestureContainer mas_makeConstraints:^(MASConstraintMaker *make) { + make.center.mas_equalTo(self.bannerContainer); + make.top.bottom.mas_equalTo(self.bannerContainer); + make.width.mas_equalTo(self.bannerContainer.mas_width).multipliedBy(2.0/3.0); + }]; + + [self.bannerLeftTapGestureContainer mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.leading.bottom.mas_equalTo(self.bannerContainer); + make.trailing.mas_equalTo(self.bannerSwipeGestureContainer.mas_leading); + }]; + + [self.bannerRightTapGestureContainer mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.trailing.bottom.mas_equalTo(self.bannerContainer); + make.leading.mas_equalTo(self.bannerSwipeGestureContainer.mas_trailing); + }]; + + // 创建中央区域的 swipe 手势(2/3 宽度) + UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self + action:@selector(handleSwipe)]; + if (isMSRTL()) { + swipe.direction = UISwipeGestureRecognizerDirectionRight; + } else { + swipe.direction = UISwipeGestureRecognizerDirectionLeft; + } + swipe.delegate = self; + + // 创建左侧区域的 tap 手势(1/6 宽度) + UITapGestureRecognizer *leftTap = [[UITapGestureRecognizer alloc] initWithTarget:self + action:@selector(handleBannerTap:)]; + leftTap.delegate = self; + + // 创建右侧区域的 tap 手势(1/6 宽度) + UITapGestureRecognizer *rightTap = [[UITapGestureRecognizer alloc] initWithTarget:self + action:@selector(handleBannerTap:)]; + rightTap.delegate = self; + + // 添加手势识别器到对应的手势容器 + [self.bannerSwipeGestureContainer addGestureRecognizer:swipe]; + [self.bannerLeftTapGestureContainer addGestureRecognizer:leftTap]; + [self.bannerRightTapGestureContainer addGestureRecognizer:rightTap]; +} +``` + +#### 2. 区域划分逻辑 +```objc +- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { + CGPoint touchPoint = [touch locationInView:self.bannerContainer]; + CGFloat containerWidth = self.bannerContainer.bounds.size.width; + + // 计算区域边界 + CGFloat leftBoundary = containerWidth / 6.0; // 1/6 宽度 + CGFloat rightBoundary = containerWidth * 5.0 / 6.0; // 5/6 宽度 + + if ([gestureRecognizer isKindOfClass:[UISwipeGestureRecognizer class]]) { + // Swipe 手势只在中央 2/3 区域生效 + return touchPoint.x >= leftBoundary && touchPoint.x <= rightBoundary; + } else if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) { + // Tap 手势只在左右两侧 1/6 区域生效 + return touchPoint.x < leftBoundary || touchPoint.x > rightBoundary; + } + + return YES; +} +``` + +#### 3. Tap 手势处理逻辑 +```objc +- (void)handleBannerTap:(UITapGestureRecognizer *)tapGesture { + CGPoint tapPoint = [tapGesture locationInView:self.bannerContainer]; + + // 检查当前显示的 banner 是否在 tap 位置可以响应事件 + if ([self isPointInBannerInteractiveArea:tapPoint]) { + // banner 可以响应,不处理,让 banner 继续原有逻辑 + NSLog(@"🎯 Banner tap 位置在可交互区域,banner 将处理此事件"); + return; + } else { + // banner 不能响应,保存 tap 位置 + self.savedTapPoint = tapPoint; + self.hasSavedTapPoint = YES; + NSLog(@"💾 Banner tap 位置不在可交互区域,已保存位置: %@", NSStringFromCGPoint(tapPoint)); + } +} +``` + +#### 4. Banner 交互区域检查 +```objc +- (BOOL)isPointInBannerInteractiveArea:(CGPoint)point { + // 检查当前显示的 banner 是否在指定位置可以响应事件 + for (UIView *subview in self.bannerContainer.subviews) { + if (subview.hidden || subview.alpha <= 0.01) { + continue; + } + + // 检查点是否在子视图范围内 + if (CGRectContainsPoint(subview.bounds, point)) { + // 检查子视图是否支持用户交互 + if (subview.userInteractionEnabled) { + // 进一步检查子视图是否有可点击的元素 + CGPoint subviewPoint = [subview convertPoint:point fromView:self.bannerContainer]; + UIView *hitView = [subview hitTest:subviewPoint withEvent:nil]; + if (hitView && hitView.userInteractionEnabled) { + return YES; + } + } + } + } + return NO; +} +``` + +#### 5. 公共接口方法 +```objc +// 获取保存的 tap 位置 +- (CGPoint)getSavedTapPoint; + +// 检查是否有保存的 tap 位置 +- (BOOL)hasSavedTapPointAvailable; + +// 清除保存的 tap 位置 +- (void)clearSavedTapPoint; +``` + +### 新增属性 +```objc +// Banner 手势相关属性 +@property(nonatomic, assign) CGPoint savedTapPoint; +@property(nonatomic, assign) BOOL hasSavedTapPoint; + +// 手势容器(使用普通UIView避免XPRoomAnimationHitView的hitTest冲突) +@property(nonatomic, strong) UIView *bannerSwipeGestureContainer; +@property(nonatomic, strong) UIView *bannerLeftTapGestureContainer; +@property(nonatomic, strong) UIView *bannerRightTapGestureContainer; +``` + +### 协议支持 +- 添加了 `UIGestureRecognizerDelegate` 协议支持 +- 实现了手势识别器的 delegate 方法 + +## 技术特点 + +### 1. 精确的区域控制 +- 使用独立的手势容器精确划分区域 +- 中央 2/3 区域:swipe 手势容器 +- 左右两侧各 1/6 区域:tap 手势容器 + +### 2. 避免手势冲突 +- 使用普通 `UIView` 作为手势容器,避免 `XPRoomAnimationHitView` 的 `hitTest` 冲突 +- 手势容器独立于 banner 内容,确保手势识别不受干扰 + +### 3. 智能的事件处理 +- 检查 banner 是否在 tap 位置可响应 +- 自动判断是否需要保存 tap 位置 +- 避免与 banner 原有交互逻辑冲突 + +### 4. 灵活的接口设计 +- 提供公共方法获取保存的 tap 位置 +- 支持清除保存的位置 +- 便于外部代码使用 + +### 5. 完善的日志记录 +- 详细记录手势处理过程 +- 便于调试和问题排查 + +## 使用示例 + +```objc +// 检查是否有保存的 tap 位置 +if ([roomAnimationView hasSavedTapPointAvailable]) { + CGPoint savedPoint = [roomAnimationView getSavedTapPoint]; + NSLog(@"保存的 tap 位置: %@", NSStringFromCGPoint(savedPoint)); + + // 使用保存的位置进行后续处理 + // ... + + // 清除保存的位置 + [roomAnimationView clearSavedTapPoint]; +} +``` + +## 注意事项 + +1. **手势容器设计**:使用普通 `UIView` 作为手势容器,避免 `XPRoomAnimationHitView` 的 `hitTest` 冲突 +2. **区域划分**:通过独立的视图容器精确划分手势区域,确保手势识别不受干扰 +3. **交互检查**:通过 `hitTest` 方法检查子视图的实际可交互性 +4. **内存管理**:及时清除不需要的 tap 位置数据 +5. **调试支持**:在 DEBUG 模式下为手势容器添加背景色,便于调试区域划分 + +## 测试建议 + +1. **区域划分测试**: + - 在中央区域测试 swipe 手势 + - 在左右两侧测试 tap 手势 + - 验证手势在错误区域不触发 + +2. **交互逻辑测试**: + - 在有可交互 banner 的区域 tap + - 在无可交互 banner 的区域 tap + - 验证 tap 位置的保存和清除 + +3. **边界条件测试**: + - 测试不同屏幕尺寸下的区域划分 + - 测试 RTL 语言环境下的手势方向 + - 测试多个 banner 同时显示的情况 + +## 总结 + +本次优化成功实现了: +- ✅ bannerContainer 手势范围的精确划分 +- ✅ 智能的 tap 手势处理逻辑 +- ✅ 灵活的 tap 位置保存机制 +- ✅ 完善的公共接口设计 +- ✅ 与现有代码的良好兼容性 +- ✅ 解决了 XPRoomAnimationHitView 的手势冲突问题 + +### 关键改进 +1. **避免手势冲突**:使用普通 `UIView` 作为手势容器,避免 `XPRoomAnimationHitView` 的 `hitTest` 方法干扰 +2. **精确区域控制**:通过独立的视图容器实现精确的手势区域划分 +3. **调试友好**:在 DEBUG 模式下为手势容器添加背景色,便于调试 + +该方案既满足了新的功能需求,又解决了潜在的手势冲突问题,保持了代码的可维护性和扩展性。 diff --git a/YuMi/Modules/YMMine/View/SubViews/CPGiftBanner.m b/YuMi/Modules/YMMine/View/SubViews/CPGiftBanner.m index ba0135ed..d23c3ec4 100644 --- a/YuMi/Modules/YMMine/View/SubViews/CPGiftBanner.m +++ b/YuMi/Modules/YMMine/View/SubViews/CPGiftBanner.m @@ -90,24 +90,24 @@ CGFloat width = KScreenWidth; CGFloat height = kGetScaleWidth(145); - CGFloat topSpace = kGetScaleWidth(67); +// CGFloat topSpace = kGetScaleWidth(67); CPGiftBanner *bannerView = [[CPGiftBanner alloc] initWithFrame:CGRectMake(KScreenWidth, 0, width, height)]; bannerView.bannerAttachment = attachment; bannerView.completeDisplay = complete; [superView addSubview:bannerView]; - - [bannerView addNotification]; @kWeakify(bannerView); // 使用 POP 动画移动 banner 到目标位置 [bannerView popEnterAnimation:^(BOOL finished) { if (finished) { + @kStrongify(bannerView); + [bannerView addNotification]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - @kStrongify(bannerView); [bannerView popLeaveAnimation:^(bool finished) { if (bannerView.completeDisplay) { bannerView.completeDisplay(); } + [bannerView removeNotification]; [bannerView removeFromSuperview]; }]; }); @@ -115,15 +115,38 @@ }]; } +- (void)handleTapNotification:(NSNotification *)note { + NSValue *value = note.userInfo[@"point"]; + CGPoint point = [value CGPointValue]; + + // 将 banner 中的点转换为屏幕坐标系 + CGPoint screenPoint = [self convertPoint:point toView:nil]; + + // 发送通知给 FunctionContainer 处理,传递屏幕坐标 + [[NSNotificationCenter defaultCenter] postNotificationName:@"BannerTapToFunctionContainer" + object:nil + userInfo:@{@"point": [NSValue valueWithCGPoint:screenPoint]}]; +} + +- (void)handleSwipeNotification { + [self dismissBanner]; +} + - (void)addNotification { - @kWeakify(self); - [[NSNotificationCenter defaultCenter] addObserverForName:@"SwipeOutBanner" - object:nil - queue:[NSOperationQueue mainQueue] - usingBlock:^(NSNotification * _Nonnull notification) { - @kStrongify(self); - [self dismissBanner]; - }]; + + [[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 { diff --git a/YuMi/Modules/YMNewHome/View/XPNewHomeViewController.m b/YuMi/Modules/YMNewHome/View/XPNewHomeViewController.m index 817f565a..cb4034ca 100644 --- a/YuMi/Modules/YMNewHome/View/XPNewHomeViewController.m +++ b/YuMi/Modules/YMNewHome/View/XPNewHomeViewController.m @@ -13,6 +13,7 @@ #import #import #import "SDWebImageManager.h" +#import ///Tool #import "Api+Home.h" #import "YUMIMacroUitls.h" @@ -24,6 +25,7 @@ #import "TTPopup.h" #import "NSArray+Safe.h" #import "XPWeakTimer.h" +#import "XPRoomAnimationHitView.h" ///Model #import "HomeTagModel.h" #import "AccountModel.h" @@ -663,21 +665,34 @@ XPHomeRecommendOtherRoomViewDelegate> #pragma mark - JXPagerMainTableViewGestureDelegate - (BOOL)mainTableViewGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { - //禁止categoryView左右滑动的时候,上下和左右都可以滚动 + // 优化手势冲突处理逻辑 + + // 1. 禁止categoryView左右滑动的时候,上下和左右都可以滚动 if (otherGestureRecognizer.view == self.pagingView.listContainerView) { return NO; } + + // 2. 处理特定tag的视图手势冲突 if(otherGestureRecognizer.view.tag == 9000001){ return NO; } if(otherGestureRecognizer.view.tag == 9000002){ return NO; } - if(otherGestureRecognizer.view.tag == 98777){ return NO; } + +// // 3. 处理RoomAnimationView的banner手势冲突 +// // 检查otherGestureRecognizer是否来自RoomAnimationView的bannerContainer +// if ([otherGestureRecognizer.view isKindOfClass:[XPRoomAnimationHitView class]] && +// [NSStringFromClass([otherGestureRecognizer.view class]) containsString:@"XPRoomAnimationHitView"]) { +// // 如果是bannerContainer的手势,允许同时识别,但优先级较低 +// NSLog(@"🎯 JXPagerView与Banner手势冲突处理: 允许同时识别"); +// return YES; +// } + // 4. 默认处理:只允许Pan手势同时识别 return [gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]] && [otherGestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]; } #pragma mark - XPHomeContainerProtocol diff --git a/YuMi/Modules/YMRoom/View/AnimationView/GameUniversalBannerView.m b/YuMi/Modules/YMRoom/View/AnimationView/GameUniversalBannerView.m index 1e811135..988fd0f0 100644 --- a/YuMi/Modules/YMRoom/View/AnimationView/GameUniversalBannerView.m +++ b/YuMi/Modules/YMRoom/View/AnimationView/GameUniversalBannerView.m @@ -47,17 +47,17 @@ bannerView.gameID = model.skipContent; [superView addSubview:bannerView]; - [bannerView addNotification]; - @kWeakify(bannerView); [bannerView popEnterAnimation:^(BOOL finished) { + @kStrongify(bannerView); + [bannerView addNotification]; if (finished && bannerView.alreadyCancel == NO) { - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - @kStrongify(bannerView); + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [bannerView popLeaveAnimation:^(bool finished) { if (bannerView.completeDisplay) { bannerView.completeDisplay(); } + [bannerView removeNotification]; [bannerView removeFromSuperview]; }]; }); @@ -65,15 +65,49 @@ }]; } +- (void)handleSwipeNotification { + [self dismissBanner]; +} + +- (void)handleTapNotification:(NSNotification *)note { + NSValue *value = note.userInfo[@"point"]; + CGPoint point = [value CGPointValue]; + + NSLog(@"🔄 GameUniversalBannerView: 接收到点击点 %@ (bannerContainer坐标系)", NSStringFromCGPoint(point)); + + // 将 bannerContainer 坐标系中的点转换为 GameUniversalBannerView 坐标系中的点 + CGPoint bannerPoint = [self convertPoint:point fromView:self.superview]; + + NSLog(@"🔄 GameUniversalBannerView: 转换为 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(@"🎯 GameUniversalBannerView: 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 { - @kWeakify(self); - [[NSNotificationCenter defaultCenter] addObserverForName:@"SwipeOutBanner" - object:nil - queue:[NSOperationQueue mainQueue] - usingBlock:^(NSNotification * _Nonnull notification) { - @kStrongify(self); - [self dismissBanner]; - }]; + [[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 { @@ -358,16 +392,16 @@ } // 在主实现体内添加事件穿透逻辑 -- (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; -} +//- (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 diff --git a/YuMi/Modules/YMRoom/View/AnimationView/LuckyGiftWinningBannerView.m b/YuMi/Modules/YMRoom/View/AnimationView/LuckyGiftWinningBannerView.m index 09489153..0a8c5128 100644 --- a/YuMi/Modules/YMRoom/View/AnimationView/LuckyGiftWinningBannerView.m +++ b/YuMi/Modules/YMRoom/View/AnimationView/LuckyGiftWinningBannerView.m @@ -73,6 +73,11 @@ static const CGFloat kBannerTopMargin = 0;// 80.0f; @implementation LuckyGiftWinningBannerView +- (void)dealloc +{ + +} + + (void)display:(UIView *)superView inRoomUid:(NSInteger)roomUid with:(AttachmentModel *)attachment @@ -102,34 +107,70 @@ exitCurrentRoom:(void(^)(void))exit { bannerView.currentRoomUid = roomUid; [superView addSubview:bannerView]; - [bannerView addNotification]; NSInteger time = 3; -//#if DEBUG -// time = 3000; -//#endif + @kWeakify(bannerView); [bannerView popEnterAnimation:^(BOOL finished) { + @kStrongify(bannerView); + [bannerView addNotification]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(time * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - @kStrongify(bannerView); [bannerView popLeaveAnimation:^(bool finished) { if (bannerView.completeDisplay) { bannerView.completeDisplay(); } + [bannerView removeNotification]; [bannerView removeFromSuperview]; }]; }); }]; } +- (void)handleSwipeNotification { + [self dismissBanner]; +} + +- (void)handleTapNotification:(NSNotification *)note { + NSValue *value = note.userInfo[@"point"]; + CGPoint point = [value CGPointValue]; + // 计算中央 2/3 区域 + CGFloat totalW = KScreenWidth; + CGFloat regionW = totalW * 2.0 / 3.0; + CGFloat originX = (totalW - regionW) / 2.0; + + CGRect centerRegion = CGRectMake(originX, + 0, // 高度不做限制就填 0 + regionW, + self.bounds.size.height); + + if (CGRectContainsPoint(centerRegion, point)) { + NSLog(@" Banner tap 点落在中央 2/3 区域"); + [self handelTap]; + } else { + NSLog(@" Banner tap 点不落在中央 2/3 区域"); + // 将 banner 中的点转换为屏幕坐标系 + CGPoint screenPoint = [self convertPoint:point toView:nil]; + + // 发送通知给 FunctionContainer 处理,传递屏幕坐标 + [[NSNotificationCenter defaultCenter] postNotificationName:@"BannerTapToFunctionContainer" + object:nil + userInfo:@{@"point": [NSValue valueWithCGPoint:screenPoint]}]; + } +} + - (void)addNotification { - @kWeakify(self); - [[NSNotificationCenter defaultCenter] addObserverForName:@"SwipeOutBanner" - object:nil - queue:[NSOperationQueue mainQueue] - usingBlock:^(NSNotification * _Nonnull notification) { - @kStrongify(self); - [self dismissBanner]; - }]; + [[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 { @@ -189,7 +230,7 @@ exitCurrentRoom:(void(^)(void))exit { [b mas_remakeConstraints:^(MASConstraintMaker *make) { make.edges.mas_equalTo(self); }]; - [b addTarget:self action:@selector(handelTap) forControlEvents:UIControlEventTouchUpInside]; +// [b addTarget:self action:@selector(handelTap) forControlEvents:UIControlEventTouchUpInside]; } return self; } diff --git a/YuMi/Modules/YMRoom/View/AnimationView/RoomAnimationView.m b/YuMi/Modules/YMRoom/View/AnimationView/RoomAnimationView.m index 652f5cc0..2154c73e 100644 --- a/YuMi/Modules/YMRoom/View/AnimationView/RoomAnimationView.m +++ b/YuMi/Modules/YMRoom/View/AnimationView/RoomAnimationView.m @@ -91,7 +91,8 @@ XPRoomLuckyBigPrizeViewDelegate, PIRoomGiftBroadcastWindowDelegate, XPRoomAnchorRankBannerViewDelegate, -XPRoomGraffitiGiftAnimationViewDelegate +XPRoomGraffitiGiftAnimationViewDelegate, +UIGestureRecognizerDelegate > @property (nonatomic, weak) idhostDelegate; @@ -104,6 +105,9 @@ XPRoomGraffitiGiftAnimationViewDelegate @property (nonatomic, strong) XPRoomAnimationHitView *topContainer; @property (nonatomic, strong) XPRoomAnimationHitView *bannerContainer; +@property (nonatomic, strong) UIView *bannerSwipeGestureContainer; +@property (nonatomic, strong) UIView *bannerLeftTapGestureContainer; +@property (nonatomic, strong) UIView *bannerRightTapGestureContainer; /// --- 进场 /// 存放进房待播放动画的"队列"(这里用数组模拟队列 FIFO) @@ -160,8 +164,11 @@ XPRoomGraffitiGiftAnimationViewDelegate @property (nonatomic,strong) SVGAImageView *luckyGiftEffectView; ///福袋礼物送礼物的特效 @property (nonatomic, strong) VAPView *luckyVapGiftEffectView; ///福袋礼物VAP特效 -//@property(nonatomic, strong) PIUniversalBannerView *tempUniversalBanner; // 防止内存没有被持有而过早回收 @property(nonatomic, strong) NSMutableArray * universalBannerViewCaches; + +// Banner 手势相关属性 +@property(nonatomic, assign) CGPoint savedTapPoint; +@property(nonatomic, assign) BOOL hasSavedTapPoint; @end @implementation RoomAnimationView @@ -219,6 +226,8 @@ XPRoomGraffitiGiftAnimationViewDelegate [self setupBanner]; [self setupCar]; [self setupOldMethods]; + + [self addBnnerContainGesture]; } - (void)setupUI { @@ -258,676 +267,8 @@ XPRoomGraffitiGiftAnimationViewDelegate - (void)setupBanner { _roomBannertModelsQueueV2 = [NSMutableArray array]; - // 新方案:启用区域化Banner手势系统 - [self setupZonedBannerGesture]; } -#pragma mark - Zoned Banner Gesture System - -- (void)setupZonedBannerGesture { - NSLog(@"🚀 新方案: 启用区域化Banner手势系统"); - - // 1. 添加中央区域滑动手势 - UIPanGestureRecognizer *centerPanGesture = - [[UIPanGestureRecognizer alloc] initWithTarget:self - action:@selector(handleCenterPan:)]; - centerPanGesture.delegate = self; - centerPanGesture.minimumNumberOfTouches = 1; - centerPanGesture.maximumNumberOfTouches = 1; - [self.bannerContainer addGestureRecognizer:centerPanGesture]; - - // 2. 添加中央区域点击手势(备选) - UITapGestureRecognizer *centerTapGesture = - [[UITapGestureRecognizer alloc] initWithTarget:self - action:@selector(handleCenterTap:)]; - centerTapGesture.delegate = self; - [self.bannerContainer addGestureRecognizer:centerTapGesture]; - - // 3. 添加左右区域点击手势 - UITapGestureRecognizer *leftTapGesture = - [[UITapGestureRecognizer alloc] initWithTarget:self - action:@selector(handleLeftTap:)]; - leftTapGesture.delegate = self; - [self.bannerContainer addGestureRecognizer:leftTapGesture]; - - UITapGestureRecognizer *rightTapGesture = - [[UITapGestureRecognizer alloc] initWithTarget:self - action:@selector(handleRightTap:)]; - rightTapGesture.delegate = self; - [self.bannerContainer addGestureRecognizer:rightTapGesture]; - - // 4. 设置手势优先级:中央区域Pan优先于Tap - [centerTapGesture requireGestureRecognizerToFail:centerPanGesture]; - - // 5. 手势事件传递配置 - centerPanGesture.cancelsTouchesInView = NO; - centerPanGesture.delaysTouchesBegan = NO; - centerPanGesture.delaysTouchesEnded = NO; - - centerTapGesture.cancelsTouchesInView = NO; - centerTapGesture.delaysTouchesBegan = NO; - centerTapGesture.delaysTouchesEnded = NO; - - leftTapGesture.cancelsTouchesInView = NO; - leftTapGesture.delaysTouchesBegan = NO; - leftTapGesture.delaysTouchesEnded = NO; - - rightTapGesture.cancelsTouchesInView = NO; - rightTapGesture.delaysTouchesBegan = NO; - rightTapGesture.delaysTouchesEnded = NO; - - NSLog(@"✅ 区域化Banner手势配置完成"); - NSLog(@" - 中央区域: Pan手势 + Tap手势(备选)"); - NSLog(@" - 左右区域: Tap手势(透传)"); - NSLog(@" - 手势优先级: 中央Pan优先于中央Tap"); - NSLog(@" - bannerContainer手势数量: %ld", (long)self.bannerContainer.gestureRecognizers.count); - - // 验证手势识别器是否正确添加 - for (UIGestureRecognizer *gesture in self.bannerContainer.gestureRecognizers) { - NSLog(@" - 手势: %@ (delegate: %@)", NSStringFromClass([gesture class]), gesture.delegate ? @"已设置" : @"未设置"); - } - - // 确保bannerContainer可以接收用户交互 - self.bannerContainer.userInteractionEnabled = YES; - NSLog(@"🔧 bannerContainer用户交互已启用: %@", self.bannerContainer.userInteractionEnabled ? @"是" : @"否"); - - // 检查并启用所有Banner子视图的用户交互 - for (UIView *subview in self.bannerContainer.subviews) { - if (!subview.userInteractionEnabled) { - subview.userInteractionEnabled = YES; - NSLog(@"🔧 启用Banner子视图用户交互: %@", NSStringFromClass([subview class])); - } - - // 特别处理LuckyGiftWinningBannerView的按钮冲突 - if ([NSStringFromClass([subview class]) containsString:@"LuckyGiftWinningBannerView"]) { - NSLog(@"🔧 检测到LuckyGiftWinningBannerView,将在配置方法中处理"); - } - } - - // 验证手势识别器状态 - NSLog(@"🔧 手势识别器验证:"); - NSLog(@" - bannerContainer手势数量: %ld", (long)self.bannerContainer.gestureRecognizers.count); - for (UIGestureRecognizer *gesture in self.bannerContainer.gestureRecognizers) { - NSLog(@" - 手势: %@ (enabled: %@, delegate: %@)", - NSStringFromClass([gesture class]), - gesture.enabled ? @"是" : @"否", - gesture.delegate ? @"已设置" : @"未设置"); - } -} - -#pragma mark - Zone Calculation - -- (CGRect)getCenterZone { - CGFloat containerWidth = self.bannerContainer.bounds.size.width; - CGFloat centerWidth = containerWidth * 2.0 / 3.0; // 2/3 容器宽度 - CGFloat centerX = (containerWidth - centerWidth) / 2.0; - - return CGRectMake(centerX, 0, centerWidth, self.bannerContainer.bounds.size.height); -} - -- (CGRect)getLeftZone { - CGFloat containerWidth = self.bannerContainer.bounds.size.width; - CGFloat zoneWidth = containerWidth / 6.0; // 1/6 容器宽度 - - return CGRectMake(0, 0, zoneWidth, self.bannerContainer.bounds.size.height); -} - -- (CGRect)getRightZone { - CGFloat containerWidth = self.bannerContainer.bounds.size.width; - CGFloat zoneWidth = containerWidth / 6.0; // 1/6 容器宽度 - CGFloat rightX = containerWidth - zoneWidth; - - return CGRectMake(rightX, 0, zoneWidth, self.bannerContainer.bounds.size.height); -} - -- (BannerZone)getZoneForPoint:(CGPoint)point { - CGRect centerZone = [self getCenterZone]; - CGRect leftZone = [self getLeftZone]; - CGRect rightZone = [self getRightZone]; - - NSLog(@"🎯 区域计算 - 触摸点:(%.1f,%.1f)", point.x, point.y); - NSLog(@" - 中央区域: (%.1f,%.1f,%.1f,%.1f)", centerZone.origin.x, centerZone.origin.y, centerZone.size.width, centerZone.size.height); - NSLog(@" - 左侧区域: (%.1f,%.1f,%.1f,%.1f)", leftZone.origin.x, leftZone.origin.y, leftZone.size.width, leftZone.size.height); - NSLog(@" - 右侧区域: (%.1f,%.1f,%.1f,%.1f)", rightZone.origin.x, rightZone.origin.y, rightZone.size.width, rightZone.size.height); - - if (CGRectContainsPoint(centerZone, point)) { - NSLog(@"🎯 触摸点在中央区域"); - return BannerZoneCenter; - } else if (CGRectContainsPoint(leftZone, point)) { - NSLog(@"🎯 触摸点在左侧区域"); - return BannerZoneLeft; - } else if (CGRectContainsPoint(rightZone, point)) { - NSLog(@"🎯 触摸点在右侧区域"); - return BannerZoneRight; - } - - NSLog(@"🎯 触摸点在无效区域"); - return BannerZoneNone; -} - -#pragma mark - UIGestureRecognizerDelegate - -- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { - NSLog(@"🎯 shouldReceiveTouch被调用 - 手势:%@ 触摸:%p", NSStringFromClass([gestureRecognizer class]), touch); - - CGPoint touchPoint = [touch locationInView:self.bannerContainer]; - BannerZone zone = [self getZoneForPoint:touchPoint]; - - // 检查触摸的目标视图 - UIView *hitView = [self.bannerContainer hitTest:touchPoint withEvent:nil]; - NSString *hitViewClass = hitView ? NSStringFromClass([hitView class]) : @"nil"; - - // 检查触摸事件是否被拦截 - if (hitView && hitView != self.bannerContainer) { - NSLog(@"🎯 触摸被视图拦截: %@", hitViewClass); - // 检查拦截视图的用户交互设置 - NSLog(@"🎯 拦截视图用户交互: %@", hitView.userInteractionEnabled ? @"启用" : @"禁用"); - - // 特别检查GameUniversalBannerView - if ([hitViewClass containsString:@"GameUniversalBannerView"]) { - NSLog(@"🎯 GameUniversalBannerView拦截了触摸事件"); - } - } - - NSString *gestureType = @"Unknown"; - if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) { - gestureType = @"Pan"; - } else if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) { - gestureType = @"Tap"; - } - - NSString *zoneName = @"None"; - switch (zone) { - case BannerZoneCenter: zoneName = @"Center"; break; - case BannerZoneLeft: zoneName = @"Left"; break; - case BannerZoneRight: zoneName = @"Right"; break; - case BannerZoneNone: zoneName = @"None"; break; - } - - NSLog(@"🎯 Banner手势判断: %@手势 - 触摸点:(%.1f,%.1f) 区域:%@ hitView:%@", - gestureType, touchPoint.x, touchPoint.y, zoneName, hitViewClass); - - // 检查是否在有效区域内 - if (zone == BannerZoneNone) { - NSLog(@"🎯 ❌ %@手势在有效区域外被拒绝", gestureType); - return NO; - } - - // 额外检查:确保触摸点确实在bannerContainer的边界内 - if (!CGRectContainsPoint(self.bannerContainer.bounds, touchPoint)) { - NSLog(@"🎯 ❌ %@手势在bannerContainer边界外被拒绝 - 触摸点:(%.1f,%.1f) 容器边界:(%.1f,%.1f,%.1f,%.1f)", - gestureType, touchPoint.x, touchPoint.y, - self.bannerContainer.bounds.origin.x, self.bannerContainer.bounds.origin.y, - self.bannerContainer.bounds.size.width, self.bannerContainer.bounds.size.height); - return NO; - } - - // 根据手势类型和区域进行判断 - if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) { - // Pan手势只在中央区域允许,且优先于按钮点击 - if (zone == BannerZoneCenter) { - if ([hitView isKindOfClass:[UIButton class]]) { - NSLog(@"🎯 ✅ Pan手势在中央区域按钮上被允许(滑动优先)"); - } else { - NSLog(@"🎯 ✅ Pan手势在中央区域被允许"); - } - return YES; - } else { - NSLog(@"🎯 ❌ Pan手势在%@区域被拒绝", zoneName); - return NO; - } - } - - if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) { - // Tap手势:在按钮区域拒绝,在其他区域允许 - if ([hitView isKindOfClass:[UIButton class]]) { - NSLog(@"🎯 ❌ Tap手势在按钮区域被拒绝(保护按钮点击)"); - return NO; - } - - NSLog(@"🎯 ✅ Tap手势在%@区域被允许", zoneName); - return YES; - } - - NSLog(@"🎯 ❌ 未知手势类型被拒绝"); - return NO; -} - -- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer -shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { - // 允许同时识别,通过 shouldReceiveTouch 精确控制 - NSLog(@"🎯 手势同时识别: %@ 与 %@", - NSStringFromClass([gestureRecognizer class]), - NSStringFromClass([otherGestureRecognizer class])); - return YES; -} - -- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { - NSString *gestureType = @"Unknown"; - if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) { - gestureType = @"Pan"; - } else if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) { - gestureType = @"Tap"; - } - - NSLog(@"🎯 手势开始检查: %@手势 - ShouldBegin被调用", gestureType); - - // 检查Banner容器状态 - if (!self.bannerContainer.userInteractionEnabled) { - NSLog(@"🎯 ❌ Banner容器交互被禁用"); - return NO; - } - - // 检查是否有Banner显示 - if (self.bannerContainer.subviews.count == 0) { - NSLog(@"🎯 ❌ 没有Banner子视图"); - return NO; - } - - // 检查Banner容器是否可见且有效 - if (self.bannerContainer.hidden || self.bannerContainer.alpha <= 0.01) { - NSLog(@"🎯 ❌ Banner容器不可见"); - return NO; - } - - // 检查Banner容器是否有有效的frame - if (CGRectIsEmpty(self.bannerContainer.frame) || CGRectIsNull(self.bannerContainer.frame)) { - NSLog(@"🎯 ❌ Banner容器frame无效"); - return NO; - } - - NSLog(@"🎯 ✅ %@手势允许开始", gestureType); - return YES; -} - -#pragma mark - Gesture Handlers - -- (void)handleCenterPan:(UIPanGestureRecognizer *)gesture { - static NSInteger callCount = 0; - callCount++; - NSLog(@"🔥 中央区域Pan手势 - 第%ld次", (long)callCount); - NSLog(@"🔥 Pan手势被触发!手势状态: %ld", (long)gesture.state); - NSLog(@"🔥 Pan手势视图: %@", gesture.view); - - // 检查是否有Banner显示 - if (self.bannerContainer.subviews.count == 0) { - NSLog(@"🔥 ❌ 没有Banner显示,忽略手势"); - return; - } - - NSString *stateString = @"Unknown"; - switch (gesture.state) { - case UIGestureRecognizerStatePossible: stateString = @"Possible"; break; - case UIGestureRecognizerStateBegan: stateString = @"Began"; break; - case UIGestureRecognizerStateChanged: stateString = @"Changed"; break; - case UIGestureRecognizerStateEnded: stateString = @"Ended"; break; - case UIGestureRecognizerStateCancelled: stateString = @"Cancelled"; break; - case UIGestureRecognizerStateFailed: stateString = @"Failed"; break; - } - - CGPoint velocity = [gesture velocityInView:self.bannerContainer]; - CGPoint translation = [gesture translationInView:self.bannerContainer]; - - NSLog(@"👆 中央区域滑动状态: %@ - 速度:(%.1f,%.1f) 距离:(%.1f,%.1f)", - stateString, velocity.x, velocity.y, translation.x, translation.y); - - static const CGFloat kVelocityThreshold = 500.0; - static const CGFloat kDistanceThreshold = 100.0; - - switch (gesture.state) { - case UIGestureRecognizerStateBegan: - NSLog(@"✅ 中央区域滑动: 开始识别 - RTL: %@", isMSRTL() ? @"是" : @"否"); - break; - - case UIGestureRecognizerStateChanged: { - BOOL isHorizontalSwipe = fabs(velocity.x) > fabs(velocity.y); - BOOL isCorrectDirection = isMSRTL() ? (velocity.x > 0) : (velocity.x < 0); - BOOL isEnoughVelocity = fabs(velocity.x) > kVelocityThreshold; - BOOL isEnoughDistance = fabs(translation.x) > kDistanceThreshold; - - if (isHorizontalSwipe && isCorrectDirection && - (isEnoughVelocity || isEnoughDistance)) { - NSLog(@"✅ 中央区域滑动: 满足移除条件 - 速度:%.1f 距离:%.1f", fabs(velocity.x), fabs(translation.x)); - [self handleSwipeOutBanner]; - gesture.state = UIGestureRecognizerStateEnded; - } - break; - } - - case UIGestureRecognizerStateEnded: - case UIGestureRecognizerStateCancelled: - NSLog(@"👆 中央区域滑动: 结束"); - break; - - default: - break; - } -} - -- (void)handleCenterTap:(UITapGestureRecognizer *)gesture { - CGPoint touchPoint = [gesture locationInView:self.bannerContainer]; - NSLog(@"🎯 中央区域点击: 传递到Banner处理 - 触摸点:(%.1f,%.1f)", touchPoint.x, touchPoint.y); - - // 检查是否有Banner显示 - if (self.bannerContainer.subviews.count == 0) { - NSLog(@"🎯 ❌ 没有Banner显示,忽略点击"); - return; - } - - // 传递点击事件到Banner内部处理 - [self forwardTapToBanner:touchPoint]; -} - -- (void)handleLeftTap:(UITapGestureRecognizer *)gesture { - CGPoint touchPoint = [gesture locationInView:self.bannerContainer]; - if (touchPoint.x > KScreenWidth/2) { - NSLog(@"🎯 左侧区域点击: 不是左侧区域 - 触摸点:(%.1f,%.1f)", touchPoint.x, touchPoint.y); - return; - } - NSLog(@"🎯 左侧区域点击: 检查Banner处理能力 - 触摸点:(%.1f,%.1f)", touchPoint.x, touchPoint.y); - - // 检查是否有Banner显示 - if (self.bannerContainer.subviews.count == 0) { - NSLog(@"🎯 ❌ 没有Banner显示,忽略点击"); - return; - } - - // 先尝试让Banner处理,不能处理则透传 - if (![self forwardTapToBanner:touchPoint]) { - NSLog(@"📱 左侧区域点击: Banner无法处理,透传到底部"); - [self simulatePassthroughTap:touchPoint]; - } -} - -- (void)handleRightTap:(UITapGestureRecognizer *)gesture { - CGPoint touchPoint = [gesture locationInView:self.bannerContainer]; - if (touchPoint.x < KScreenWidth/2) { - NSLog(@"🎯 右侧区域点击: 不是右侧区域 - 触摸点:(%.1f,%.1f)", touchPoint.x, touchPoint.y); - return; - } - NSLog(@"🎯 右侧区域点击: 检查Banner处理能力 - 触摸点:(%.1f,%.1f)", touchPoint.x, touchPoint.y); - - // 检查是否有Banner显示 - if (self.bannerContainer.subviews.count == 0) { - NSLog(@"🎯 ❌ 没有Banner显示,忽略点击"); - return; - } - - // 先尝试让Banner处理,不能处理则透传 - if (![self forwardTapToBanner:touchPoint]) { - NSLog(@"📱 右侧区域点击: Banner无法处理,透传到底部"); - [self simulatePassthroughTap:touchPoint]; - } -} - -#pragma mark - Event Forwarding - -- (BOOL)forwardTapToBanner:(CGPoint)point { - // 查找Banner子视图 - UIView *bannerView = nil; - for (UIView *subview in self.bannerContainer.subviews) { - if (CGRectContainsPoint(subview.frame, point)) { - bannerView = subview; - break; - } - } - - if (bannerView) { - // 转换坐标到Banner视图 - CGPoint bannerPoint = [bannerView convertPoint:point fromView:self.bannerContainer]; - - // 查找可点击的目标 - UIView *targetView = [bannerView hitTest:bannerPoint withEvent:nil]; - - if ([targetView isKindOfClass:[UIButton class]]) { - UIButton *button = (UIButton *)targetView; - [button sendActionsForControlEvents:UIControlEventTouchUpInside]; - NSLog(@"🎯 Banner处理点击: 触发按钮 %@", button.titleLabel.text ?: @"(无标题)"); - return YES; - } else if (targetView && targetView != bannerView) { - NSLog(@"🎯 Banner处理点击: 找到目标视图 %@", NSStringFromClass([targetView class])); - return YES; - } - } - - NSLog(@"🎯 Banner处理点击: 无法处理"); - return NO; -} - -- (void)simulatePassthroughTap:(CGPoint)point { - UIView *hostView = nil; - if ([self.hostDelegate respondsToSelector:@selector(getSuperView)]) { - hostView = [self.hostDelegate getSuperView]; - } - - if (!hostView) { - NSLog(@"📱 Banner穿透点击: 无法获取主视图"); - return; - } - - CGPoint convertedPoint = [hostView convertPoint:point fromView:self.bannerContainer]; - - XPRoomFunctionContainerView *functionView = nil; - for (UIView *subview in hostView.subviews) { - if ([NSStringFromClass([subview class]) containsString:@"XPRoomFunctionContainerView"]) { - functionView = (XPRoomFunctionContainerView *)subview; - break; - } - } - - if (functionView) { - CGPoint functionPoint = [functionView convertPoint:convertedPoint fromView:hostView]; - - if (CGRectContainsPoint(functionView.bounds, functionPoint)) { - UIView *targetView = [functionView hitTest:functionPoint withEvent:nil]; - - if ([targetView isKindOfClass:[UIButton class]]) { - UIButton *button = (UIButton *)targetView; - [button sendActionsForControlEvents:UIControlEventTouchUpInside]; - NSLog(@"📱 Banner穿透点击: 成功触发底部按钮 %@", button.titleLabel.text ?: @"(无标题)"); - } else if ([NSStringFromClass([targetView class]) containsString:@"MSRoomOnLineView"] || - [targetView.superview isKindOfClass:[MSRoomOnLineView class]]) { - // 直接调用XPRoomFunctionContainerView的onlineTapRecognizer方法 - if ([functionView respondsToSelector:@selector(onlineTapRecognizer)]) { - [functionView performSelector:@selector(onlineTapRecognizer)]; - NSLog(@"📱 Banner穿透点击: 成功触发MSRoomOnLineView的onlineTapRecognizer"); - } else { - NSLog(@"📱 Banner穿透点击: 无法找到onlineTapRecognizer方法"); - } - } else if ([NSStringFromClass([targetView class]) containsString:@"XPRoomRankEntranceView"] || - [targetView.superview isKindOfClass:[XPRoomRankEntranceView class]]) { - // 触发贡献榜手势 - if ([functionView respondsToSelector:@selector(contributionButtonAction:)]) { - [functionView performSelector:@selector(contributionButtonAction:) withObject:nil]; - NSLog(@"📱 Banner穿透点击: 成功触发XPRoomRankEntranceView的contributionButtonAction"); - } - } else if ([NSStringFromClass([targetView class]) containsString:@"XPRoomAnchorRankEnterView"] || - [targetView.superview isKindOfClass:[XPRoomAnchorRankEnterView class]]) { - // 触发小时榜手势 - if ([functionView respondsToSelector:@selector(onAnchorHourRankButtonAction:)]) { - [functionView performSelector:@selector(onAnchorHourRankButtonAction:) withObject:nil]; - NSLog(@"📱 Banner穿透点击: 成功触发XPRoomAnchorRankEnterView的onAnchorHourRankButtonAction"); - } - } else if ([NSStringFromClass([targetView class]) containsString:@"XPAnchorFansTeamEntranceView"]) { - // 触发粉丝团手势 - if ([functionView respondsToSelector:@selector(tapFansTeamRecognizer)]) { - [functionView performSelector:@selector(tapFansTeamRecognizer)]; - NSLog(@"📱 Banner穿透点击: 成功触发XPAnchorFansTeamEntranceView的tapFansTeamRecognizer"); - } - } else if (targetView) { - NSLog(@"📱 Banner穿透点击: 找到目标视图但不是按钮: %@", NSStringFromClass([targetView class])); - } else { - NSLog(@"📱 Banner穿透点击: 在功能容器范围内但未找到可点击目标"); - } - } else { - NSLog(@"📱 Banner穿透点击: 点击位置不在功能容器范围内"); - } - } else { - NSLog(@"📱 Banner穿透点击: 未找到功能容器"); - } -} - -- (void)handleSwipeOutBanner { - NSLog(@"🚨 发送SwipeOutBanner通知 - 当前状态: isRoomBannerV2Displaying=%@", self.isRoomBannerV2Displaying ? @"YES" : @"NO"); - - // 防止重复处理 - if (!self.isRoomBannerV2Displaying) { - NSLog(@"🚨 警告: 尝试关闭banner但状态显示没有正在显示的banner"); - return; - } - - // 立即设置状态为NO,防止重复处理 - self.isRoomBannerV2Displaying = NO; - - [[NSNotificationCenter defaultCenter] postNotificationName:@"SwipeOutBanner" object:nil]; - - // 延迟处理下一个banner,确保当前banner完全关闭 - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - [self processNextRoomEffectAttachment]; - }); -} - -#pragma mark - Banner Interaction Management - -- (void)configureBannerInteraction:(UIView *)bannerView { - NSString *bannerClassName = NSStringFromClass([bannerView class]); - NSLog(@"🔧 配置Banner交互: %@", bannerClassName); - - // 确保Banner可以接收用户交互 - bannerView.userInteractionEnabled = YES; - - // 根据Banner类型进行特殊处理 - if ([bannerClassName containsString:@"LuckyGiftWinningBannerView"]) { - NSLog(@"🔧 LuckyGiftWinningBannerView: 处理按钮冲突"); - // 查找覆盖按钮并记录 - for (UIView *subview in bannerView.subviews) { - if ([subview isKindOfClass:[UIButton class]]) { - NSLog(@"🔧 找到LuckyGiftWinningBannerView覆盖按钮"); - } - } - - // 确保Pan手势优先于按钮点击 - for (UIGestureRecognizer *gesture in self.bannerContainer.gestureRecognizers) { - if ([gesture isKindOfClass:[UIPanGestureRecognizer class]]) { - gesture.cancelsTouchesInView = YES; - NSLog(@"🔧 设置Pan手势cancelsTouchesInView = YES (LuckyGiftWinningBannerView)"); - } - } - } else if ([bannerClassName containsString:@"GameUniversalBannerView"]) { - NSLog(@"🔧 GameUniversalBannerView: 确保交互启用"); - // 确保所有子视图都可以交互 - [self enableInteractionForView:bannerView]; - - // 检查GameUniversalBannerView是否有自己的手势识别器 - NSLog(@"🔧 GameUniversalBannerView手势识别器数量: %ld", (long)bannerView.gestureRecognizers.count); - for (UIGestureRecognizer *gesture in bannerView.gestureRecognizers) { - NSLog(@"🔧 GameUniversalBannerView手势: %@ (enabled: %@)", - NSStringFromClass([gesture class]), - gesture.enabled ? @"是" : @"否"); - } - } else if ([bannerClassName containsString:@"RoomHighValueGiftBannerAnimation"]) { - NSLog(@"🔧 RoomHighValueGiftBannerAnimation: 确保交互启用"); - // 确保所有子视图都可以交互 - [self enableInteractionForView:bannerView]; - - // 检查RoomHighValueGiftBannerAnimation是否有自己的手势识别器 - NSLog(@"🔧 RoomHighValueGiftBannerAnimation手势识别器数量: %ld", (long)bannerView.gestureRecognizers.count); - for (UIGestureRecognizer *gesture in bannerView.gestureRecognizers) { - NSLog(@"🔧 RoomHighValueGiftBannerAnimation手势: %@ (enabled: %@)", - NSStringFromClass([gesture class]), - gesture.enabled ? @"是" : @"否"); - } - - // 确保Pan手势优先于按钮点击 - for (UIGestureRecognizer *gesture in self.bannerContainer.gestureRecognizers) { - if ([gesture isKindOfClass:[UIPanGestureRecognizer class]]) { - gesture.cancelsTouchesInView = YES; - NSLog(@"🔧 设置Pan手势cancelsTouchesInView = YES (RoomHighValueGiftBannerAnimation)"); - } - } - } else if ([bannerClassName containsString:@"BravoGiftBannerView"]) { - NSLog(@"🔧 BravoGiftBannerView: 确保交互启用"); - // 确保所有子视图都可以交互 - [self enableInteractionForView:bannerView]; - - // 检查BravoGiftBannerView是否有自己的手势识别器 - NSLog(@"🔧 BravoGiftBannerView手势识别器数量: %ld", (long)bannerView.gestureRecognizers.count); - for (UIGestureRecognizer *gesture in bannerView.gestureRecognizers) { - NSLog(@"🔧 BravoGiftBannerView手势: %@ (enabled: %@)", - NSStringFromClass([gesture class]), - gesture.enabled ? @"是" : @"否"); - } - - // 确保Pan手势优先于按钮点击 - for (UIGestureRecognizer *gesture in self.bannerContainer.gestureRecognizers) { - if ([gesture isKindOfClass:[UIPanGestureRecognizer class]]) { - gesture.cancelsTouchesInView = YES; - NSLog(@"🔧 设置Pan手势cancelsTouchesInView = YES (BravoGiftBannerView)"); - } - } - } else if ([bannerClassName containsString:@"LuckyPackageBannerView"]) { - NSLog(@"🔧 LuckyPackageBannerView: 确保交互启用"); - // 确保所有子视图都可以交互 - [self enableInteractionForView:bannerView]; - - // 检查LuckyPackageBannerView是否有自己的手势识别器 - NSLog(@"🔧 LuckyPackageBannerView手势识别器数量: %ld", (long)bannerView.gestureRecognizers.count); - for (UIGestureRecognizer *gesture in bannerView.gestureRecognizers) { - NSLog(@"🔧 LuckyPackageBannerView手势: %@ (enabled: %@)", - NSStringFromClass([gesture class]), - gesture.enabled ? @"是" : @"否"); - } - - // 确保Pan手势优先于按钮点击 - for (UIGestureRecognizer *gesture in self.bannerContainer.gestureRecognizers) { - if ([gesture isKindOfClass:[UIPanGestureRecognizer class]]) { - gesture.cancelsTouchesInView = YES; - NSLog(@"🔧 设置Pan手势cancelsTouchesInView = YES (LuckyPackageBannerView)"); - } - } - } else if ([bannerClassName containsString:@"CPGiftBanner"]) { - NSLog(@"🔧 CPGiftBanner: 确保交互启用"); - // 确保所有子视图都可以交互 - [self enableInteractionForView:bannerView]; - - // 检查CPGiftBanner是否有自己的手势识别器 - NSLog(@"🔧 CPGiftBanner手势识别器数量: %ld", (long)bannerView.gestureRecognizers.count); - for (UIGestureRecognizer *gesture in bannerView.gestureRecognizers) { - NSLog(@"🔧 CPGiftBanner手势: %@ (enabled: %@)", - NSStringFromClass([gesture class]), - gesture.enabled ? @"是" : @"否"); - } - - // 确保Pan手势优先于按钮点击 - for (UIGestureRecognizer *gesture in self.bannerContainer.gestureRecognizers) { - if ([gesture isKindOfClass:[UIPanGestureRecognizer class]]) { - gesture.cancelsTouchesInView = YES; - NSLog(@"🔧 设置Pan手势cancelsTouchesInView = YES (CPGiftBanner)"); - } - } - } else { - // 默认处理:确保所有banner都能响应手势 - NSLog(@"🔧 默认Banner处理: %@", bannerClassName); - [self enableInteractionForView:bannerView]; - - // 确保Pan手势优先于按钮点击 - for (UIGestureRecognizer *gesture in self.bannerContainer.gestureRecognizers) { - if ([gesture isKindOfClass:[UIPanGestureRecognizer class]]) { - gesture.cancelsTouchesInView = YES; - NSLog(@"🔧 设置Pan手势cancelsTouchesInView = YES (默认处理)"); - } - } - } -} - -- (void)enableInteractionForView:(UIView *)view { - view.userInteractionEnabled = YES; - - for (UIView *subview in view.subviews) { - subview.userInteractionEnabled = YES; - [self enableInteractionForView:subview]; - } -} #pragma mark - Legacy Support @@ -1160,17 +501,17 @@ shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherG return; } - #if 0 + #if DEBUG // DEBUG环境:复制banner数据用于测试 - BOOL enableBannerCopy = YES; // 设置为NO可以禁用复制功能 + BOOL enableBannerCopy = obj.second == Custom_Message_Sub_Super_Gift_Banner;// YES; // 设置为NO可以禁用复制功能 NSInteger copyCount = 10; // 可以调整这个数字来改变复制数量 - if (enableBannerCopy) { - NSLog(@"🧪 DEBUG环境:收到banner数据,复制%ld份用于测试", (long)copyCount); - NSLog(@"🧪 原始banner类型: %@", NSStringFromClass([obj class])); + if (enableBannerCopy) { + NSLog(@"🧪 DEBUG环境:收到banner数据,复制%ld份用于测试", (long)copyCount); + NSLog(@"🧪 原始banner类型: %@", NSStringFromClass([obj class])); // 添加原始数据 - [self.roomBannertModelsQueueV2 addObject:obj]; + [self.roomBannertModelsQueueV2 addObject:obj]; // 复制指定份数 for (int i = 1; i < copyCount; i++) { @@ -1223,7 +564,6 @@ shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherG } } - - (void)sortBannerQueue { RoomInfoModel *roomInfo = self.hostDelegate.getRoomInfo; NSString *currentRoomUid = @(roomInfo.uid).stringValue; @@ -1287,24 +627,13 @@ shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherG // 清理之前的banner,防止多个banner同时显示(保留debug视图) NSMutableArray *viewsToRemove = [NSMutableArray array]; for (UIView *subview in self.bannerContainer.subviews) { - // 保留debug视图(tag为999的视图) - if (subview.tag == 999) { - NSLog(@"🔄 保留debug视图: %@", NSStringFromClass([subview class])); - } else { - // 其他视图都是banner,需要移除 - [viewsToRemove addObject:subview]; - NSLog(@"🔄 标记移除banner: %@", NSStringFromClass([subview class])); - } + [viewsToRemove addObject:subview]; + NSLog(@"🔄 标记移除banner: %@", NSStringFromClass([subview class])); } for (UIView *view in viewsToRemove) { [view removeFromSuperview]; } - - NSLog(@"🔄 清理了 %ld 个banner视图,保留debug视图", (long)viewsToRemove.count); - - // 确保debug视图存在 -// [self ensureDebugViewsExist]; switch (nextAttachment.second) { case Custom_Message_Sub_General_Floating_Screen_One_Room: @@ -1359,16 +688,6 @@ shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherG @kStrongify(self); [self.hostDelegate exitRoom]; }]; - - // 延迟配置Banner交互,确保Banner已添加到视图层级 - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - for (UIView *subview in self.bannerContainer.subviews) { - if ([NSStringFromClass([subview class]) containsString:@"BravoGiftBannerView"]) { - [self configureBannerInteraction:subview]; - break; - } - } - }); } - (void)playLuckyPackageBanner:(AttachmentModel *)obj { @@ -1392,16 +711,6 @@ shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherG @kStrongify(self); [self.hostDelegate exitRoom]; }]; - - // 延迟配置Banner交互,确保Banner已添加到视图层级 - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - for (UIView *subview in self.bannerContainer.subviews) { - if ([NSStringFromClass([subview class]) containsString:@"LuckyPackageBannerView"]) { - [self configureBannerInteraction:subview]; - break; - } - } - }); } - (void)receiveRoomGiftBanner:(AttachmentModel *)obj { @@ -1424,16 +733,6 @@ shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherG self.isRoomBannerV2Displaying = NO; [self processNextRoomEffectAttachment]; }]; - - // 延迟配置Banner交互,确保Banner已添加到视图层级 - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - for (UIView *subview in self.bannerContainer.subviews) { - if ([NSStringFromClass([subview class]) containsString:@"RoomHighValueGiftBannerAnimation"]) { - [self configureBannerInteraction:subview]; - break; - } - } - }); } - (void)receiveCPEvent:(AttachmentModel *)attachment { @@ -1461,16 +760,6 @@ shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherG self.isRoomBannerV2Displaying = NO; [self processNextRoomEffectAttachment]; }]; - - // 延迟配置Banner交互,确保Banner已添加到视图层级 - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - for (UIView *subview in self.bannerContainer.subviews) { - if ([NSStringFromClass([subview class]) containsString:@"CPGiftBanner"]) { - [self configureBannerInteraction:subview]; - break; - } - } - }); } - (void)playCPLevelUp:(AttachmentModel *)attachMent { @@ -1495,9 +784,9 @@ shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherG - (void)receiveBravoGiftWinning:(AttachmentModel *)attachment { RoomInfoModel *roomInfo = self.hostDelegate.getRoomInfo; BravoGiftWinningFlagViewModel *flagModel = [BravoGiftWinningFlagView display:self.topContainer - with:attachment - roomID:roomInfo.roomId - uID:[AccountInfoStorage instance].getUid]; + with:attachment + roomID:roomInfo.roomId + uID:[AccountInfoStorage instance].getUid]; if (flagModel.roomId != roomInfo.roomId || flagModel.uid != [AccountInfoStorage instance].getUid.integerValue) { return; } @@ -1528,15 +817,18 @@ shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherG } NSString *svgaItemName = @""; SVGAVideoEntity *entity; + svgaItemName = @"大"; + entity = self.broveSVGAEntity_lv_3; + /* switch (level) { -// case 1: -// svgaItemName = @"小"; -// entity = self.broveSVGAEntity_lv_1; -// break; -// case 2: -// svgaItemName = @"中"; -// entity = self.broveSVGAEntity_lv_2; -// break; + case 1: + svgaItemName = @"小"; + entity = self.broveSVGAEntity_lv_1; + break; + case 2: + svgaItemName = @"中"; + entity = self.broveSVGAEntity_lv_2; + break; case 3: svgaItemName = @"大"; entity = self.broveSVGAEntity_lv_3; @@ -1545,7 +837,7 @@ shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherG default: break; } - + */ if ([NSString isEmpty:svgaItemName]) { return; } @@ -1565,13 +857,15 @@ shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherG inBundle:[NSBundle mainBundle] completionBlock:^(SVGAVideoEntity * _Nonnull videoItem) { @kStrongify(self); + self.broveSVGAEntity_lv_3 = videoItem; + /* switch (level) { -// case 1: -// self.broveSVGAEntity_lv_1 = videoItem; -// break; -// case 2: -// self.broveSVGAEntity_lv_2 = videoItem; -// break; + case 1: + self.broveSVGAEntity_lv_1 = videoItem; + break; + case 2: + self.broveSVGAEntity_lv_2 = videoItem; + break; case 3: self.broveSVGAEntity_lv_3 = videoItem; break; @@ -1579,6 +873,7 @@ shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherG default: break; } + */ [self startPlayBroveSVGA:svgaView level:level]; } failureBlock:^(NSError * _Nonnull error) { @@ -1642,16 +937,6 @@ shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherG @kStrongify(self); [self.hostDelegate exitRoom]; }]; - - // 延迟配置Banner交互,确保Banner已添加到视图层级 - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - for (UIView *subview in self.bannerContainer.subviews) { - if ([NSStringFromClass([subview class]) containsString:@"LuckyGiftWinningBannerView"]) { - [self configureBannerInteraction:subview]; - break; - } - } - }); } -(void)receiveRoomGeneralFloatingScreen:(AttachmentModel *)attachment{ @@ -1710,26 +995,6 @@ shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherG } } }]; - - // 延迟配置Banner交互,确保Banner已添加到视图层级 - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - for (UIView *subview in self.bannerContainer.subviews) { - if ([NSStringFromClass([subview class]) containsString:@"GameUniversalBannerView"]) { - [self configureBannerInteraction:subview]; - - // 验证bannerContainer的手势识别器 - NSLog(@"🔧 Banner显示后验证:"); - NSLog(@" - bannerContainer手势数量: %ld", (long)self.bannerContainer.gestureRecognizers.count); - for (UIGestureRecognizer *gesture in self.bannerContainer.gestureRecognizers) { - NSLog(@" - 手势: %@ (enabled: %@, delegate: %@)", - NSStringFromClass([gesture class]), - gesture.enabled ? @"是" : @"否", - gesture.delegate ? @"已设置" : @"未设置"); - } - break; - } - } - }); } #pragma mark - Method: Car @@ -2895,9 +2160,28 @@ shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherG } #pragma mark - Gesture -// 注释掉整个方法 -/* - (void)addBnnerContainGesture { + [self insertSubview:self.bannerSwipeGestureContainer aboveSubview:self.bannerContainer]; + [self insertSubview:self.bannerLeftTapGestureContainer aboveSubview:self.bannerContainer]; + [self insertSubview:self.bannerRightTapGestureContainer aboveSubview:self.bannerContainer]; + + [self.bannerSwipeGestureContainer mas_makeConstraints:^(MASConstraintMaker *make) { + make.center.mas_equalTo(self.bannerContainer); + make.top.bottom.mas_equalTo(self.bannerContainer); + make.width.mas_equalTo(self.bannerContainer.mas_width).multipliedBy(2.0/3.0); + }]; + + [self.bannerLeftTapGestureContainer mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.leading.bottom.mas_equalTo(self.bannerContainer); + make.trailing.mas_equalTo(self.bannerSwipeGestureContainer.mas_leading); + }]; + + [self.bannerRightTapGestureContainer mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.trailing.bottom.mas_equalTo(self.bannerContainer); + make.leading.mas_equalTo(self.bannerSwipeGestureContainer.mas_trailing); + }]; + + // 创建中央区域的 swipe 手势(2/3 宽度) UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipe)]; if (isMSRTL()) { @@ -2905,15 +2189,118 @@ shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherG } else { swipe.direction = UISwipeGestureRecognizerDirectionLeft; } + swipe.delegate = self; - [self.bannerContainer addGestureRecognizer:swipe]; + // 创建中央区域的 tap 手势(2/3 宽度) + UITapGestureRecognizer *centerTap = [[UITapGestureRecognizer alloc] initWithTarget:self + action:@selector(handleBannerTap:)]; + centerTap.delegate = self; + + // 创建左侧区域的 tap 手势(1/6 宽度) + UITapGestureRecognizer *leftTap = [[UITapGestureRecognizer alloc] initWithTarget:self + action:@selector(handleBannerTap:)]; + leftTap.delegate = self; + + // 创建右侧区域的 tap 手势(1/6 宽度) + UITapGestureRecognizer *rightTap = [[UITapGestureRecognizer alloc] initWithTarget:self + action:@selector(handleBannerTap:)]; + rightTap.delegate = self; + + // 只有当 swipe 判定失败后,tap 才允许成功 + [centerTap requireGestureRecognizerToFail:swipe]; + + // 添加手势识别器 + [self.bannerSwipeGestureContainer addGestureRecognizer:swipe]; + [self.bannerSwipeGestureContainer addGestureRecognizer:centerTap]; + [self.bannerLeftTapGestureContainer addGestureRecognizer:leftTap]; + [self.bannerRightTapGestureContainer addGestureRecognizer:rightTap]; } -*/ - (void)handleSwipe { [[NSNotificationCenter defaultCenter] postNotificationName:@"SwipeOutBanner" object:nil]; } +- (void)handleBannerTap:(UITapGestureRecognizer *)tapGesture { + CGPoint tapPoint = [tapGesture locationInView:self.bannerContainer]; + + // 检查当前显示的 banner 是否在 tap 位置可以响应事件 + if ([self isPointInBannerInteractiveArea:tapPoint]) { + // banner 可以响应,不处理,让 banner 继续原有逻辑 + NSLog(@"🎯 Banner tap 位置在可交互区域,banner 将处理此事件"); + [[NSNotificationCenter defaultCenter] postNotificationName:@"TapBanner" + object:nil + userInfo:@{@"point": [NSValue valueWithCGPoint:tapPoint]}]; + } else { + // banner 不能响应,保存 tap 位置 + self.savedTapPoint = tapPoint; + self.hasSavedTapPoint = YES; + NSLog(@"💾 Banner tap 位置不在可交互区域,已保存位置: %@", NSStringFromCGPoint(tapPoint)); + // 将 bannerContainer 中的点转换为屏幕坐标系 + CGPoint screenPoint = [self.bannerContainer convertPoint:tapPoint toView:nil]; +// UIView *tappedView = tapGesture.view; + [[NSNotificationCenter defaultCenter] postNotificationName:@"BannerTapToFunctionContainer" + object:nil + userInfo:@{@"point": [NSValue valueWithCGPoint:screenPoint]}]; + } +} + +- (BOOL)isPointInBannerInteractiveArea:(CGPoint)point { + // 检查当前显示的 banner 是否在指定位置可以响应事件 + for (UIView *subview in self.bannerContainer.subviews) { + if (subview.hidden || subview.alpha <= 0.01) { + continue; + } + + // 检查点是否在子视图范围内 + if (CGRectContainsPoint(subview.bounds, point)) { + // 检查子视图是否支持用户交互 + if (subview.userInteractionEnabled) { + // 进一步检查子视图是否有可点击的元素 + CGPoint subviewPoint = [subview convertPoint:point fromView:self.bannerContainer]; + UIView *hitView = [subview hitTest:subviewPoint withEvent:nil]; + if (hitView && hitView.userInteractionEnabled) { + return YES; + } + } + } + } + return NO; +} + +#pragma mark - UIGestureRecognizerDelegate + +- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { + // 允许手势同时识别 + return YES; +} + +- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { + CGPoint touchPoint = [touch locationInView:self.bannerContainer]; + CGFloat containerWidth = self.bannerContainer.bounds.size.width; + + // 计算区域边界 + CGFloat leftBoundary = containerWidth / 6.0; // 1/6 宽度 + CGFloat rightBoundary = containerWidth * 5.0 / 6.0; // 5/6 宽度 + + if ([gestureRecognizer isKindOfClass:[UISwipeGestureRecognizer class]]) { + // Swipe 手势只在中央 2/3 区域生效 + return touchPoint.x >= leftBoundary && touchPoint.x <= rightBoundary; + } else if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) { + // Tap 手势只在左右两侧 1/6 区域生效 +// return touchPoint.x < leftBoundary || touchPoint.x > rightBoundary; + // 根据手势所在的容器来决定区域 + if (gestureRecognizer.view == self.bannerSwipeGestureContainer) { + // 中央区域的 tap 手势 + return touchPoint.x >= leftBoundary && touchPoint.x <= rightBoundary; + } else { + // 左右两侧的 tap 手势 + return touchPoint.x < leftBoundary || touchPoint.x > rightBoundary; + } + } + + return YES; +} + #pragma mark - Animations - (void)enterRoomAnimationFor:(UIView *)targetView startFrom:(CGPoint)sfPoint @@ -3080,10 +2467,46 @@ shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherG - (XPRoomAnimationHitView *)bannerContainer { if (!_bannerContainer) { _bannerContainer = [[XPRoomAnimationHitView alloc] init]; +#if DEBUG + _bannerContainer.backgroundColor = [UIColor colorWithWhite:0.8 alpha:0.4]; +#endif } return _bannerContainer; } +- (UIView *)bannerSwipeGestureContainer { + if (!_bannerSwipeGestureContainer) { + _bannerSwipeGestureContainer = [[UIView alloc] init]; + _bannerSwipeGestureContainer.userInteractionEnabled = YES; +#if DEBUG + _bannerSwipeGestureContainer.backgroundColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:0.4]; +#endif + } + return _bannerSwipeGestureContainer; +} + +- (UIView *)bannerLeftTapGestureContainer { + if (!_bannerLeftTapGestureContainer) { + _bannerLeftTapGestureContainer = [[UIView alloc] init]; + _bannerLeftTapGestureContainer.userInteractionEnabled = YES; +#if DEBUG + _bannerLeftTapGestureContainer.backgroundColor = [UIColor colorWithRed:0 green:1 blue:0 alpha:0.4]; +#endif + } + return _bannerLeftTapGestureContainer; +} + +- (UIView *)bannerRightTapGestureContainer { + if (!_bannerRightTapGestureContainer) { + _bannerRightTapGestureContainer = [[UIView alloc] init]; + _bannerRightTapGestureContainer.userInteractionEnabled = YES; +#if DEBUG + _bannerRightTapGestureContainer.backgroundColor = [UIColor colorWithRed:0 green:0 blue:1 alpha:0.4]; +#endif + } + return _bannerRightTapGestureContainer; +} + - (SVGAImageView *)enterEffectView { if (_enterEffectView == nil) { _enterEffectView = [[SVGAImageView alloc]init]; @@ -4034,32 +3457,21 @@ shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherG #pragma mark - Touch Event Handling -- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { - // 检查是否有banner显示 - if (self.bannerContainer.subviews.count == 0) { - NSLog(@"🎯 没有banner显示,不接收触摸事件"); - return NO; - } - - // 检查banner容器是否可见 - if (self.bannerContainer.hidden || self.bannerContainer.alpha <= 0.01) { - NSLog(@"🎯 banner容器不可见,不接收触摸事件"); - return NO; - } - - // 检查触摸点是否在bannerContainer区域内 - CGPoint bannerPoint = [self.bannerContainer convertPoint:point fromView:self]; - if (CGRectContainsPoint(self.bannerContainer.bounds, bannerPoint)) { - NSLog(@"🎯 触摸在banner区域内,接收触摸事件"); - return [super pointInside:point withEvent:event]; - } - - // 在banner区域外,不接收触摸事件,让下层视图处理 - NSLog(@"🎯 触摸在banner区域外,穿透到下层视图 - 触摸点:(%.1f,%.1f) banner区域:(%.1f,%.1f,%.1f,%.1f)", - point.x, point.y, - self.bannerContainer.frame.origin.x, self.bannerContainer.frame.origin.y, - self.bannerContainer.frame.size.width, self.bannerContainer.frame.size.height); - return NO; +// 移除pointInside重写,让触摸事件正常传递 + +#pragma mark - Public Methods + +- (CGPoint)getSavedTapPoint { + return self.savedTapPoint; +} + +- (BOOL)hasSavedTapPointAvailable { + return self.hasSavedTapPoint; +} + +- (void)clearSavedTapPoint { + self.hasSavedTapPoint = NO; + self.savedTapPoint = CGPointZero; } @end diff --git a/YuMi/Modules/YMRoom/View/AnimationView/RoomHighValueGiftBannerAnimation.m b/YuMi/Modules/YMRoom/View/AnimationView/RoomHighValueGiftBannerAnimation.m index a6477a91..b06ed586 100644 --- a/YuMi/Modules/YMRoom/View/AnimationView/RoomHighValueGiftBannerAnimation.m +++ b/YuMi/Modules/YMRoom/View/AnimationView/RoomHighValueGiftBannerAnimation.m @@ -88,20 +88,21 @@ break; } - [banner addNotification]; [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(), ^{ - @kStrongify(banner); [banner popLeaveAnimation:^(bool finished) { if (banner.animationComplete) { banner.animationComplete(); } + [banner removeNotification]; [banner removeFromSuperview]; }]; }); @@ -113,15 +114,37 @@ [self.svgaImageView stopAnimation]; } +- (void)handleSwipeNotification { + [self dismissBanner]; +} + +- (void)handleTapNotification:(NSNotification *)note { + NSValue *value = note.userInfo[@"point"]; + CGPoint point = [value CGPointValue]; + + // 将 banner 中的点转换为屏幕坐标系 + CGPoint screenPoint = [self convertPoint:point toView:nil]; + + // 发送通知给 FunctionContainer 处理,传递屏幕坐标 + [[NSNotificationCenter defaultCenter] postNotificationName:@"BannerTapToFunctionContainer" + object:nil + userInfo:@{@"point": [NSValue valueWithCGPoint:screenPoint]}]; +} + - (void)addNotification { - @kWeakify(self); - [[NSNotificationCenter defaultCenter] addObserverForName:@"SwipeOutBanner" - object:nil - queue:[NSOperationQueue mainQueue] - usingBlock:^(NSNotification * _Nonnull notification) { - @kStrongify(self); - [self dismissBanner]; - }]; + [[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 { @@ -406,16 +429,16 @@ } // ========== 事件穿透实现 ========== -- (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; -} +//- (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 diff --git a/YuMi/Modules/YMRoom/View/AnimationView/XPRoomAnimationHitView.m b/YuMi/Modules/YMRoom/View/AnimationView/XPRoomAnimationHitView.m index 119d5fcf..3b4ec086 100644 --- a/YuMi/Modules/YMRoom/View/AnimationView/XPRoomAnimationHitView.m +++ b/YuMi/Modules/YMRoom/View/AnimationView/XPRoomAnimationHitView.m @@ -9,6 +9,16 @@ // MARK: 只要有子视图命中,就交给子视图处理;子视图都没命中就放弃处理,自己不接收任何触摸事件。 @implementation XPRoomAnimationHitView +//- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { +// for (NSInteger i = (self.subviews.count - 1) ; i >= 0 ; i--) { +// UIView * subView = [self.subviews xpSafeObjectAtIndex:i]; +// CGPoint convertPoint = [subView convertPoint:point fromView:self]; +// if (CGRectContainsPoint(subView.bounds, convertPoint)) { +// return [subView hitTest:convertPoint withEvent:event]; +// } +// } +// return nil; +//} - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { @@ -17,11 +27,6 @@ return nil; } - // 可选:判断点是否在自身bounds内 -// if (!CGRectContainsPoint(self.bounds, point)) { -// return nil; -// } - // 从后往前遍历子视图 for (NSInteger i = self.subviews.count - 1; i >= 0; i--) { UIView *subView = [self.subviews xpSafeObjectAtIndex:i]; @@ -35,7 +40,8 @@ } } - // 如果子视图都不响应,则不处理 + // 如果子视图都不响应,则返回nil,让触摸事件传递给下层视图 + // 这是关键:不拦截触摸事件,让它们正常传递 return nil; } diff --git a/YuMi/Modules/YMRoom/View/BaseUIContainerView/XPRoomFunctionContainerView.m b/YuMi/Modules/YMRoom/View/BaseUIContainerView/XPRoomFunctionContainerView.m index 47a5863a..92b0ada0 100644 --- a/YuMi/Modules/YMRoom/View/BaseUIContainerView/XPRoomFunctionContainerView.m +++ b/YuMi/Modules/YMRoom/View/BaseUIContainerView/XPRoomFunctionContainerView.m @@ -174,11 +174,94 @@ [self initSubViews]; [self initSubViewConstraints]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(beginMatchAnchorPK:) name:@"anchorPKMatchBegin" object:nil]; - + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleTapToFunctionContainer:) name:@"BannerTapToFunctionContainer" object:nil]; } return self; } +- (void)handleTapToFunctionContainer:(NSNotification *)note { + NSValue *tapPointValue = note.userInfo[@"point"]; +// UIView *bannerContainer = note.userInfo[@"gesture container"]; + + if (!tapPointValue) { + return; + } + + CGPoint tapPoint = [tapPointValue CGPointValue]; + + // 将 bannerContainer 中的点转换为 FunctionContainer 坐标系中的点 + CGPoint convertedPoint = [self convertPoint:tapPoint fromView:nil]; + + NSLog(@"�� 坐标转换: 原始点 %@ -> 转换后点 %@", NSStringFromCGPoint(tapPoint), NSStringFromCGPoint(convertedPoint)); + + // 检查点是否与各个功能视图重合 + [self checkPointIntersectionWithSubviews:convertedPoint]; +} + +- (void)checkPointIntersectionWithSubviews:(CGPoint)point { + // 检查 contributeEnterView + if (self.contributeEnterView && !self.contributeEnterView.hidden) { + CGPoint contributePoint = [self.contributeEnterView convertPoint:point fromView:self]; + if (CGRectContainsPoint(self.contributeEnterView.bounds, contributePoint)) { + NSLog(@"🎯 点击位置与 contributeEnterView 重合,触发贡献榜事件"); + [self contributionButtonAction:nil]; + return; + } + } + + // 检查 onlineView + if (self.onlineView && !self.onlineView.hidden) { + CGPoint onlinePoint = [self.onlineView convertPoint:point fromView:self]; + if (CGRectContainsPoint(self.onlineView.bounds, onlinePoint)) { + NSLog(@"🎯 点击位置与 onlineView 重合,触发在线人数事件"); + [self onlineTapRecognizer]; + return; + } + } + + // 检查 hourRankEntranceView + if (self.hourRankEntranceView && !self.hourRankEntranceView.hidden) { + CGPoint hourRankPoint = [self.hourRankEntranceView convertPoint:point fromView:self]; + if (CGRectContainsPoint(self.hourRankEntranceView.bounds, hourRankPoint)) { + NSLog(@"🎯 点击位置与 hourRankEntranceView 重合,触发小时榜事件"); + [self onAnchorHourRankButtonAction:nil]; + return; + } + } + + // 检查 fansTeamEntranceView + if (self.fansTeamEntranceView && !self.fansTeamEntranceView.hidden) { + CGPoint fansTeamPoint = [self.fansTeamEntranceView convertPoint:point fromView:self]; + if (CGRectContainsPoint(self.fansTeamEntranceView.bounds, fansTeamPoint)) { + NSLog(@"🎯 点击位置与 fansTeamEntranceView 重合,触发粉丝团事件"); + [self tapFansTeamRecognizer]; + return; + } + } + + // 检查 musicEnterButton + if (self.musicEnterButton && !self.musicEnterButton.hidden) { + CGPoint musicPoint = [self.musicEnterButton convertPoint:point fromView:self]; + if (CGRectContainsPoint(self.musicEnterButton.bounds, musicPoint)) { + NSLog(@"🎯 点击位置与 musicEnterButton 重合,触发音乐播放器事件"); + [self musicEnterButtonAction:self.musicEnterButton]; + return; + } + } + + // 检查 trumpetView(如果存在且可见) + if (self.trumpetView && !self.trumpetView.hidden) { + CGPoint trumpetPoint = [self.trumpetView convertPoint:point fromView:self]; + if (CGRectContainsPoint(self.trumpetView.bounds, trumpetPoint)) { + NSLog(@"�� 点击位置与 trumpetView 重合,触发小喇叭事件"); + // 这里需要根据 trumpetView 的具体实现来触发相应事件 + return; + } + } + + NSLog(@"❌ 点击位置未与任何功能视图重合"); +} + - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { // 先检查自身状态 if (!self.userInteractionEnabled || self.hidden || self.alpha <= 0.01) { diff --git a/YuMi/Modules/YMRoom/View/Common/BravoGiftBannerView.m b/YuMi/Modules/YMRoom/View/Common/BravoGiftBannerView.m index 68b7781d..f1120da3 100644 --- a/YuMi/Modules/YMRoom/View/Common/BravoGiftBannerView.m +++ b/YuMi/Modules/YMRoom/View/Common/BravoGiftBannerView.m @@ -51,34 +51,73 @@ exitCurrentRoom:(void(^)(void))exit { banner.currentRoomUid = roomUid; banner.completeDisplay = complete; banner.exitCurrentRoom = exit; - [banner addNotification]; [superView addSubview:banner]; NSInteger time = 3; @kWeakify(banner); [banner popEnterAnimation:^(BOOL finished) { + @kStrongify(banner); + [banner addNotification]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(time * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - @kStrongify(banner); [banner popLeaveAnimation:^(bool finished) { if (banner.completeDisplay) { banner.completeDisplay(); } + [banner removeNotification]; [banner removeFromSuperview]; }]; }); }]; } +- (void)handleSwipeNotification { + [self dismissBanner]; +} + +- (void)handleTapNotification:(NSNotification *)note { + NSValue *value = note.userInfo[@"point"]; + CGPoint point = [value CGPointValue]; + // 计算中央 2/3 区域 + CGFloat totalW = KScreenWidth; + CGFloat regionW = totalW * 2.0 / 3.0; + CGFloat originX = (totalW - regionW) / 2.0; + + CGRect centerRegion = CGRectMake(originX, + 0, // 高度不做限制就填 0 + regionW, + self.bounds.size.height); + + if (CGRectContainsPoint(centerRegion, point)) { + NSLog(@" Banner tap 点落在中央 2/3 区域"); + [self handleTap]; + } else { + NSLog(@" Banner tap 点不落在中央 2/3 区域"); + // 将 banner 中的点转换为屏幕坐标系 + CGPoint screenPoint = [self convertPoint:point toView:nil]; + + // 发送通知给 FunctionContainer 处理,传递屏幕坐标 + [[NSNotificationCenter defaultCenter] postNotificationName:@"BannerTapToFunctionContainer" + object:nil + userInfo:@{@"point": [NSValue valueWithCGPoint:screenPoint]}]; + } +} + - (void)addNotification { - @kWeakify(self); - [[NSNotificationCenter defaultCenter] addObserverForName:@"SwipeOutBanner" - object:nil - queue:[NSOperationQueue mainQueue] - usingBlock:^(NSNotification * _Nonnull notification) { - @kStrongify(self); - [self dismissBanner]; - }]; + + [[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)setModel:(BravoGiftBannerViewModel *)model { @@ -129,18 +168,18 @@ exitCurrentRoom:(void(^)(void))exit { self = [super initWithFrame:frame]; if (self) { [self setupUI]; - self.userInteractionEnabled = NO; + self.userInteractionEnabled = YES; UIButton *b = [UIButton buttonWithType:UIButtonTypeCustom]; [self addSubview:b]; [b mas_remakeConstraints:^(MASConstraintMaker *make) { make.edges.mas_equalTo(self); }]; - [b addTarget:self action:@selector(handelTap) forControlEvents:UIControlEventTouchUpInside]; +// [b addTarget:self action:@selector(handleTap) forControlEvents:UIControlEventTouchUpInside]; } return self; } -- (void)handelTap { +- (void)handleTap { if (self.model.roomUid.integerValue == self.currentRoomUid) { return; } diff --git a/YuMi/Modules/YMRoom/View/LuckyPackage/LuckyPackageBannerView.m b/YuMi/Modules/YMRoom/View/LuckyPackage/LuckyPackageBannerView.m index 635bc61d..fbe28292 100644 --- a/YuMi/Modules/YMRoom/View/LuckyPackage/LuckyPackageBannerView.m +++ b/YuMi/Modules/YMRoom/View/LuckyPackage/LuckyPackageBannerView.m @@ -64,17 +64,19 @@ exitCurrentRoom:(void(^)(void))exit { banner.completeDisplay = complete; banner.exitCurrentRoom = exit; banner.currentRoomUid = roomUid; - [banner addNotification]; + [superView addSubview:banner]; @kWeakify(banner); [banner popEnterAnimation:^(BOOL finished) { + @kStrongify(banner); + [banner addNotification]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - @kStrongify(banner); [banner popLeaveAnimation:^(bool finished) { if (banner.completeDisplay) { banner.completeDisplay(); } + [banner removeNotification]; [banner removeFromSuperview]; }]; }); @@ -100,15 +102,50 @@ exitCurrentRoom:(void(^)(void))exit { return banner; } +- (void)handleSwipeNotification { + [self dismissBanner]; +} + +- (void)handleTapNotification:(NSNotification *)note { + NSValue *value = note.userInfo[@"point"]; + CGPoint point = [value CGPointValue]; + + NSLog(@"🔄 GameUniversalBannerView: 接收到点击点 %@ (bannerContainer坐标系)", NSStringFromCGPoint(point)); + + // 将 bannerContainer 坐标系中的点转换为 GameUniversalBannerView 坐标系中的点 + CGPoint bannerPoint = [self convertPoint:point fromView:self.superview]; + + NSLog(@"🔄 GameUniversalBannerView: 转换为 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(@"🎯 GameUniversalBannerView: 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 { - @kWeakify(self); - [[NSNotificationCenter defaultCenter] addObserverForName:@"SwipeOutBanner" - object:nil - queue:[NSOperationQueue mainQueue] - usingBlock:^(NSNotification * _Nonnull notification) { - @kStrongify(self); - [self dismissBanner]; - }]; + + [[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 {