新增 Banner 手势优化实施总结文档,记录了在 RoomAnimationView 中对 banner 手势系统的优化过程,包括手势识别器的重新设计、区域划分逻辑、tap 手势处理逻辑及交互区域检查等。同时,优化了多个视图中的通知处理逻辑,确保手势事件的准确传递与处理,提升用户交互体验。
This commit is contained in:
248
Banner手势优化实施总结.md
Normal file
248
Banner手势优化实施总结.md
Normal file
@@ -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 模式下为手势容器添加背景色,便于调试
|
||||||
|
|
||||||
|
该方案既满足了新的功能需求,又解决了潜在的手势冲突问题,保持了代码的可维护性和扩展性。
|
@@ -90,24 +90,24 @@
|
|||||||
|
|
||||||
CGFloat width = KScreenWidth;
|
CGFloat width = KScreenWidth;
|
||||||
CGFloat height = kGetScaleWidth(145);
|
CGFloat height = kGetScaleWidth(145);
|
||||||
CGFloat topSpace = kGetScaleWidth(67);
|
// CGFloat topSpace = kGetScaleWidth(67);
|
||||||
CPGiftBanner *bannerView = [[CPGiftBanner alloc] initWithFrame:CGRectMake(KScreenWidth, 0, width, height)];
|
CPGiftBanner *bannerView = [[CPGiftBanner alloc] initWithFrame:CGRectMake(KScreenWidth, 0, width, height)];
|
||||||
bannerView.bannerAttachment = attachment;
|
bannerView.bannerAttachment = attachment;
|
||||||
bannerView.completeDisplay = complete;
|
bannerView.completeDisplay = complete;
|
||||||
[superView addSubview:bannerView];
|
[superView addSubview:bannerView];
|
||||||
|
|
||||||
[bannerView addNotification];
|
|
||||||
|
|
||||||
@kWeakify(bannerView);
|
@kWeakify(bannerView);
|
||||||
// 使用 POP 动画移动 banner 到目标位置
|
// 使用 POP 动画移动 banner 到目标位置
|
||||||
[bannerView popEnterAnimation:^(BOOL finished) {
|
[bannerView popEnterAnimation:^(BOOL finished) {
|
||||||
if (finished) {
|
if (finished) {
|
||||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
||||||
@kStrongify(bannerView);
|
@kStrongify(bannerView);
|
||||||
|
[bannerView addNotification];
|
||||||
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||||
[bannerView popLeaveAnimation:^(bool finished) {
|
[bannerView popLeaveAnimation:^(bool finished) {
|
||||||
if (bannerView.completeDisplay) {
|
if (bannerView.completeDisplay) {
|
||||||
bannerView.completeDisplay();
|
bannerView.completeDisplay();
|
||||||
}
|
}
|
||||||
|
[bannerView removeNotification];
|
||||||
[bannerView removeFromSuperview];
|
[bannerView removeFromSuperview];
|
||||||
}];
|
}];
|
||||||
});
|
});
|
||||||
@@ -115,15 +115,38 @@
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)addNotification {
|
- (void)handleTapNotification:(NSNotification *)note {
|
||||||
@kWeakify(self);
|
NSValue *value = note.userInfo[@"point"];
|
||||||
[[NSNotificationCenter defaultCenter] addObserverForName:@"SwipeOutBanner"
|
CGPoint point = [value CGPointValue];
|
||||||
|
|
||||||
|
// 将 banner 中的点转换为屏幕坐标系
|
||||||
|
CGPoint screenPoint = [self convertPoint:point toView:nil];
|
||||||
|
|
||||||
|
// 发送通知给 FunctionContainer 处理,传递屏幕坐标
|
||||||
|
[[NSNotificationCenter defaultCenter] postNotificationName:@"BannerTapToFunctionContainer"
|
||||||
object:nil
|
object:nil
|
||||||
queue:[NSOperationQueue mainQueue]
|
userInfo:@{@"point": [NSValue valueWithCGPoint:screenPoint]}];
|
||||||
usingBlock:^(NSNotification * _Nonnull notification) {
|
}
|
||||||
@kStrongify(self);
|
|
||||||
|
- (void)handleSwipeNotification {
|
||||||
[self dismissBanner];
|
[self dismissBanner];
|
||||||
}];
|
}
|
||||||
|
|
||||||
|
- (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 {
|
- (void)dismissBanner {
|
||||||
|
@@ -13,6 +13,7 @@
|
|||||||
#import <JXCategoryView/JXCategoryView.h>
|
#import <JXCategoryView/JXCategoryView.h>
|
||||||
#import <MJRefresh/MJRefresh.h>
|
#import <MJRefresh/MJRefresh.h>
|
||||||
#import "SDWebImageManager.h"
|
#import "SDWebImageManager.h"
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
///Tool
|
///Tool
|
||||||
#import "Api+Home.h"
|
#import "Api+Home.h"
|
||||||
#import "YUMIMacroUitls.h"
|
#import "YUMIMacroUitls.h"
|
||||||
@@ -24,6 +25,7 @@
|
|||||||
#import "TTPopup.h"
|
#import "TTPopup.h"
|
||||||
#import "NSArray+Safe.h"
|
#import "NSArray+Safe.h"
|
||||||
#import "XPWeakTimer.h"
|
#import "XPWeakTimer.h"
|
||||||
|
#import "XPRoomAnimationHitView.h"
|
||||||
///Model
|
///Model
|
||||||
#import "HomeTagModel.h"
|
#import "HomeTagModel.h"
|
||||||
#import "AccountModel.h"
|
#import "AccountModel.h"
|
||||||
@@ -663,21 +665,34 @@ XPHomeRecommendOtherRoomViewDelegate>
|
|||||||
|
|
||||||
#pragma mark - JXPagerMainTableViewGestureDelegate
|
#pragma mark - JXPagerMainTableViewGestureDelegate
|
||||||
- (BOOL)mainTableViewGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
|
- (BOOL)mainTableViewGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
|
||||||
//禁止categoryView左右滑动的时候,上下和左右都可以滚动
|
// 优化手势冲突处理逻辑
|
||||||
|
|
||||||
|
// 1. 禁止categoryView左右滑动的时候,上下和左右都可以滚动
|
||||||
if (otherGestureRecognizer.view == self.pagingView.listContainerView) {
|
if (otherGestureRecognizer.view == self.pagingView.listContainerView) {
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2. 处理特定tag的视图手势冲突
|
||||||
if(otherGestureRecognizer.view.tag == 9000001){
|
if(otherGestureRecognizer.view.tag == 9000001){
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
if(otherGestureRecognizer.view.tag == 9000002){
|
if(otherGestureRecognizer.view.tag == 9000002){
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(otherGestureRecognizer.view.tag == 98777){
|
if(otherGestureRecognizer.view.tag == 98777){
|
||||||
return NO;
|
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]];
|
return [gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]] && [otherGestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]];
|
||||||
}
|
}
|
||||||
#pragma mark - XPHomeContainerProtocol
|
#pragma mark - XPHomeContainerProtocol
|
||||||
|
@@ -47,17 +47,17 @@
|
|||||||
bannerView.gameID = model.skipContent;
|
bannerView.gameID = model.skipContent;
|
||||||
[superView addSubview:bannerView];
|
[superView addSubview:bannerView];
|
||||||
|
|
||||||
[bannerView addNotification];
|
|
||||||
|
|
||||||
@kWeakify(bannerView);
|
@kWeakify(bannerView);
|
||||||
[bannerView popEnterAnimation:^(BOOL finished) {
|
[bannerView popEnterAnimation:^(BOOL finished) {
|
||||||
|
@kStrongify(bannerView);
|
||||||
|
[bannerView addNotification];
|
||||||
if (finished && bannerView.alreadyCancel == NO) {
|
if (finished && bannerView.alreadyCancel == NO) {
|
||||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||||
@kStrongify(bannerView);
|
|
||||||
[bannerView popLeaveAnimation:^(bool finished) {
|
[bannerView popLeaveAnimation:^(bool finished) {
|
||||||
if (bannerView.completeDisplay) {
|
if (bannerView.completeDisplay) {
|
||||||
bannerView.completeDisplay();
|
bannerView.completeDisplay();
|
||||||
}
|
}
|
||||||
|
[bannerView removeNotification];
|
||||||
[bannerView removeFromSuperview];
|
[bannerView removeFromSuperview];
|
||||||
}];
|
}];
|
||||||
});
|
});
|
||||||
@@ -65,15 +65,49 @@
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)addNotification {
|
- (void)handleSwipeNotification {
|
||||||
@kWeakify(self);
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserverForName:@"SwipeOutBanner"
|
|
||||||
object:nil
|
|
||||||
queue:[NSOperationQueue mainQueue]
|
|
||||||
usingBlock:^(NSNotification * _Nonnull notification) {
|
|
||||||
@kStrongify(self);
|
|
||||||
[self dismissBanner];
|
[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 {
|
||||||
|
[[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 {
|
- (void)dismissBanner {
|
||||||
@@ -358,16 +392,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 在主实现体内添加事件穿透逻辑
|
// 在主实现体内添加事件穿透逻辑
|
||||||
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
|
//- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
|
||||||
if (!self.userInteractionEnabled || self.hidden || self.alpha <= 0.01) {
|
// if (!self.userInteractionEnabled || self.hidden || self.alpha <= 0.01) {
|
||||||
return nil;
|
// return nil;
|
||||||
}
|
// }
|
||||||
CGPoint goButtonPoint = [self.goButton convertPoint:point fromView:self];
|
// CGPoint goButtonPoint = [self.goButton convertPoint:point fromView:self];
|
||||||
if ([self.goButton pointInside:goButtonPoint withEvent:event]) {
|
// if ([self.goButton pointInside:goButtonPoint withEvent:event]) {
|
||||||
return self.goButton;
|
// return self.goButton;
|
||||||
}
|
// }
|
||||||
// 其他区域返回self,允许触摸事件被处理(包括手势识别器)
|
// // 其他区域返回self,允许触摸事件被处理(包括手势识别器)
|
||||||
return self;
|
// return self;
|
||||||
}
|
//}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@@ -73,6 +73,11 @@ static const CGFloat kBannerTopMargin = 0;// 80.0f;
|
|||||||
|
|
||||||
@implementation LuckyGiftWinningBannerView
|
@implementation LuckyGiftWinningBannerView
|
||||||
|
|
||||||
|
- (void)dealloc
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
+ (void)display:(UIView *)superView
|
+ (void)display:(UIView *)superView
|
||||||
inRoomUid:(NSInteger)roomUid
|
inRoomUid:(NSInteger)roomUid
|
||||||
with:(AttachmentModel *)attachment
|
with:(AttachmentModel *)attachment
|
||||||
@@ -102,34 +107,70 @@ exitCurrentRoom:(void(^)(void))exit {
|
|||||||
bannerView.currentRoomUid = roomUid;
|
bannerView.currentRoomUid = roomUid;
|
||||||
[superView addSubview:bannerView];
|
[superView addSubview:bannerView];
|
||||||
|
|
||||||
[bannerView addNotification];
|
|
||||||
NSInteger time = 3;
|
NSInteger time = 3;
|
||||||
//#if DEBUG
|
|
||||||
// time = 3000;
|
|
||||||
//#endif
|
|
||||||
@kWeakify(bannerView);
|
@kWeakify(bannerView);
|
||||||
[bannerView popEnterAnimation:^(BOOL finished) {
|
[bannerView popEnterAnimation:^(BOOL finished) {
|
||||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(time * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
||||||
@kStrongify(bannerView);
|
@kStrongify(bannerView);
|
||||||
|
[bannerView addNotification];
|
||||||
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(time * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||||
[bannerView popLeaveAnimation:^(bool finished) {
|
[bannerView popLeaveAnimation:^(bool finished) {
|
||||||
if (bannerView.completeDisplay) {
|
if (bannerView.completeDisplay) {
|
||||||
bannerView.completeDisplay();
|
bannerView.completeDisplay();
|
||||||
}
|
}
|
||||||
|
[bannerView removeNotification];
|
||||||
[bannerView removeFromSuperview];
|
[bannerView removeFromSuperview];
|
||||||
}];
|
}];
|
||||||
});
|
});
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)addNotification {
|
- (void)handleSwipeNotification {
|
||||||
@kWeakify(self);
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserverForName:@"SwipeOutBanner"
|
|
||||||
object:nil
|
|
||||||
queue:[NSOperationQueue mainQueue]
|
|
||||||
usingBlock:^(NSNotification * _Nonnull notification) {
|
|
||||||
@kStrongify(self);
|
|
||||||
[self dismissBanner];
|
[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 {
|
||||||
|
[[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 {
|
- (void)dismissBanner {
|
||||||
@@ -189,7 +230,7 @@ exitCurrentRoom:(void(^)(void))exit {
|
|||||||
[b mas_remakeConstraints:^(MASConstraintMaker *make) {
|
[b mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||||
make.edges.mas_equalTo(self);
|
make.edges.mas_equalTo(self);
|
||||||
}];
|
}];
|
||||||
[b addTarget:self action:@selector(handelTap) forControlEvents:UIControlEventTouchUpInside];
|
// [b addTarget:self action:@selector(handelTap) forControlEvents:UIControlEventTouchUpInside];
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -88,20 +88,21 @@
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
[banner addNotification];
|
|
||||||
|
|
||||||
[superView addSubview:banner];
|
[superView addSubview:banner];
|
||||||
|
|
||||||
@kWeakify(banner);
|
@kWeakify(banner);
|
||||||
// 使用 POP 动画移动 banner 到目标位置
|
// 使用 POP 动画移动 banner 到目标位置
|
||||||
[banner popEnterAnimation:^(BOOL finished) {
|
[banner popEnterAnimation:^(BOOL finished) {
|
||||||
|
@kStrongify(banner);
|
||||||
|
[banner addNotification];
|
||||||
if (finished) {
|
if (finished) {
|
||||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||||
@kStrongify(banner);
|
|
||||||
[banner popLeaveAnimation:^(bool finished) {
|
[banner popLeaveAnimation:^(bool finished) {
|
||||||
if (banner.animationComplete) {
|
if (banner.animationComplete) {
|
||||||
banner.animationComplete();
|
banner.animationComplete();
|
||||||
}
|
}
|
||||||
|
[banner removeNotification];
|
||||||
[banner removeFromSuperview];
|
[banner removeFromSuperview];
|
||||||
}];
|
}];
|
||||||
});
|
});
|
||||||
@@ -113,15 +114,37 @@
|
|||||||
[self.svgaImageView stopAnimation];
|
[self.svgaImageView stopAnimation];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)addNotification {
|
- (void)handleSwipeNotification {
|
||||||
@kWeakify(self);
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserverForName:@"SwipeOutBanner"
|
|
||||||
object:nil
|
|
||||||
queue:[NSOperationQueue mainQueue]
|
|
||||||
usingBlock:^(NSNotification * _Nonnull notification) {
|
|
||||||
@kStrongify(self);
|
|
||||||
[self dismissBanner];
|
[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 {
|
||||||
|
[[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 {
|
- (void)dismissBanner {
|
||||||
@@ -406,16 +429,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ========== 事件穿透实现 ==========
|
// ========== 事件穿透实现 ==========
|
||||||
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
|
//- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
|
||||||
if (!self.userInteractionEnabled || self.hidden || self.alpha <= 0.01) {
|
// if (!self.userInteractionEnabled || self.hidden || self.alpha <= 0.01) {
|
||||||
return nil;
|
// return nil;
|
||||||
}
|
// }
|
||||||
CGPoint goButtonPoint = [self.goButton convertPoint:point fromView:self];
|
// CGPoint goButtonPoint = [self.goButton convertPoint:point fromView:self];
|
||||||
if ([self.goButton pointInside:goButtonPoint withEvent:event]) {
|
// if ([self.goButton pointInside:goButtonPoint withEvent:event]) {
|
||||||
return self.goButton;
|
// return self.goButton;
|
||||||
}
|
// }
|
||||||
// 其他区域返回self,允许触摸事件被父视图的手势识别器处理
|
// // 其他区域返回self,允许触摸事件被父视图的手势识别器处理
|
||||||
return self;
|
// return self;
|
||||||
}
|
//}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@@ -9,6 +9,16 @@
|
|||||||
// MARK: 只要有子视图命中,就交给子视图处理;子视图都没命中就放弃处理,自己不接收任何触摸事件。
|
// MARK: 只要有子视图命中,就交给子视图处理;子视图都没命中就放弃处理,自己不接收任何触摸事件。
|
||||||
@implementation XPRoomAnimationHitView
|
@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 {
|
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
|
||||||
|
|
||||||
@@ -17,11 +27,6 @@
|
|||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 可选:判断点是否在自身bounds内
|
|
||||||
// if (!CGRectContainsPoint(self.bounds, point)) {
|
|
||||||
// return nil;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 从后往前遍历子视图
|
// 从后往前遍历子视图
|
||||||
for (NSInteger i = self.subviews.count - 1; i >= 0; i--) {
|
for (NSInteger i = self.subviews.count - 1; i >= 0; i--) {
|
||||||
UIView *subView = [self.subviews xpSafeObjectAtIndex:i];
|
UIView *subView = [self.subviews xpSafeObjectAtIndex:i];
|
||||||
@@ -35,7 +40,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果子视图都不响应,则不处理
|
// 如果子视图都不响应,则返回nil,让触摸事件传递给下层视图
|
||||||
|
// 这是关键:不拦截触摸事件,让它们正常传递
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -174,11 +174,94 @@
|
|||||||
[self initSubViews];
|
[self initSubViews];
|
||||||
[self initSubViewConstraints];
|
[self initSubViewConstraints];
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(beginMatchAnchorPK:) name:@"anchorPKMatchBegin" object:nil];
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(beginMatchAnchorPK:) name:@"anchorPKMatchBegin" object:nil];
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleTapToFunctionContainer:) name:@"BannerTapToFunctionContainer" object:nil];
|
||||||
}
|
}
|
||||||
return self;
|
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(@"<22><> 坐标转换: 原始点 %@ -> 转换后点 %@", 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(@"<22><> 点击位置与 trumpetView 重合,触发小喇叭事件");
|
||||||
|
// 这里需要根据 trumpetView 的具体实现来触发相应事件
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NSLog(@"❌ 点击位置未与任何功能视图重合");
|
||||||
|
}
|
||||||
|
|
||||||
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
|
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
|
||||||
// 先检查自身状态
|
// 先检查自身状态
|
||||||
if (!self.userInteractionEnabled || self.hidden || self.alpha <= 0.01) {
|
if (!self.userInteractionEnabled || self.hidden || self.alpha <= 0.01) {
|
||||||
|
@@ -51,34 +51,73 @@ exitCurrentRoom:(void(^)(void))exit {
|
|||||||
banner.currentRoomUid = roomUid;
|
banner.currentRoomUid = roomUid;
|
||||||
banner.completeDisplay = complete;
|
banner.completeDisplay = complete;
|
||||||
banner.exitCurrentRoom = exit;
|
banner.exitCurrentRoom = exit;
|
||||||
[banner addNotification];
|
|
||||||
[superView addSubview:banner];
|
[superView addSubview:banner];
|
||||||
|
|
||||||
NSInteger time = 3;
|
NSInteger time = 3;
|
||||||
|
|
||||||
@kWeakify(banner);
|
@kWeakify(banner);
|
||||||
[banner popEnterAnimation:^(BOOL finished) {
|
[banner popEnterAnimation:^(BOOL finished) {
|
||||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(time * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
||||||
@kStrongify(banner);
|
@kStrongify(banner);
|
||||||
|
[banner addNotification];
|
||||||
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(time * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||||
[banner popLeaveAnimation:^(bool finished) {
|
[banner popLeaveAnimation:^(bool finished) {
|
||||||
if (banner.completeDisplay) {
|
if (banner.completeDisplay) {
|
||||||
banner.completeDisplay();
|
banner.completeDisplay();
|
||||||
}
|
}
|
||||||
|
[banner removeNotification];
|
||||||
[banner removeFromSuperview];
|
[banner removeFromSuperview];
|
||||||
}];
|
}];
|
||||||
});
|
});
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)addNotification {
|
- (void)handleSwipeNotification {
|
||||||
@kWeakify(self);
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserverForName:@"SwipeOutBanner"
|
|
||||||
object:nil
|
|
||||||
queue:[NSOperationQueue mainQueue]
|
|
||||||
usingBlock:^(NSNotification * _Nonnull notification) {
|
|
||||||
@kStrongify(self);
|
|
||||||
[self dismissBanner];
|
[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 {
|
||||||
|
|
||||||
|
[[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 {
|
- (void)setModel:(BravoGiftBannerViewModel *)model {
|
||||||
@@ -129,18 +168,18 @@ exitCurrentRoom:(void(^)(void))exit {
|
|||||||
self = [super initWithFrame:frame];
|
self = [super initWithFrame:frame];
|
||||||
if (self) {
|
if (self) {
|
||||||
[self setupUI];
|
[self setupUI];
|
||||||
self.userInteractionEnabled = NO;
|
self.userInteractionEnabled = YES;
|
||||||
UIButton *b = [UIButton buttonWithType:UIButtonTypeCustom];
|
UIButton *b = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||||
[self addSubview:b];
|
[self addSubview:b];
|
||||||
[b mas_remakeConstraints:^(MASConstraintMaker *make) {
|
[b mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||||
make.edges.mas_equalTo(self);
|
make.edges.mas_equalTo(self);
|
||||||
}];
|
}];
|
||||||
[b addTarget:self action:@selector(handelTap) forControlEvents:UIControlEventTouchUpInside];
|
// [b addTarget:self action:@selector(handleTap) forControlEvents:UIControlEventTouchUpInside];
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)handelTap {
|
- (void)handleTap {
|
||||||
if (self.model.roomUid.integerValue == self.currentRoomUid) {
|
if (self.model.roomUid.integerValue == self.currentRoomUid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@@ -64,17 +64,19 @@ exitCurrentRoom:(void(^)(void))exit {
|
|||||||
banner.completeDisplay = complete;
|
banner.completeDisplay = complete;
|
||||||
banner.exitCurrentRoom = exit;
|
banner.exitCurrentRoom = exit;
|
||||||
banner.currentRoomUid = roomUid;
|
banner.currentRoomUid = roomUid;
|
||||||
[banner addNotification];
|
|
||||||
[superView addSubview:banner];
|
[superView addSubview:banner];
|
||||||
|
|
||||||
@kWeakify(banner);
|
@kWeakify(banner);
|
||||||
[banner popEnterAnimation:^(BOOL finished) {
|
[banner popEnterAnimation:^(BOOL finished) {
|
||||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
||||||
@kStrongify(banner);
|
@kStrongify(banner);
|
||||||
|
[banner addNotification];
|
||||||
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||||
[banner popLeaveAnimation:^(bool finished) {
|
[banner popLeaveAnimation:^(bool finished) {
|
||||||
if (banner.completeDisplay) {
|
if (banner.completeDisplay) {
|
||||||
banner.completeDisplay();
|
banner.completeDisplay();
|
||||||
}
|
}
|
||||||
|
[banner removeNotification];
|
||||||
[banner removeFromSuperview];
|
[banner removeFromSuperview];
|
||||||
}];
|
}];
|
||||||
});
|
});
|
||||||
@@ -100,15 +102,50 @@ exitCurrentRoom:(void(^)(void))exit {
|
|||||||
return banner;
|
return banner;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)addNotification {
|
- (void)handleSwipeNotification {
|
||||||
@kWeakify(self);
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserverForName:@"SwipeOutBanner"
|
|
||||||
object:nil
|
|
||||||
queue:[NSOperationQueue mainQueue]
|
|
||||||
usingBlock:^(NSNotification * _Nonnull notification) {
|
|
||||||
@kStrongify(self);
|
|
||||||
[self dismissBanner];
|
[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 {
|
||||||
|
|
||||||
|
[[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 {
|
- (void)dismissBanner {
|
||||||
|
Reference in New Issue
Block a user