优化 XPRoomViewController 中的视图初始化逻辑,移除 stageView 的添加,调整 messageContainerView 的约束。同时,修复 BravoGiftWinningFlagView 和 LuckyGiftWinningFlagView 的位置计算,确保视图在屏幕可见范围内,增强用户体验。新增智能销毁方法以优化 RoomAnimationView 的资源管理,确保重要动画播放时的清理逻辑更加安全。
This commit is contained in:
@@ -30,7 +30,7 @@
|
||||
|
||||
+ (BravoGiftWinningFlagViewModel *)display:(UIView *)superView with:(AttachmentModel *)attachment roomID:(NSInteger)roomID uID:(NSString *)UID {
|
||||
BravoGiftWinningFlagViewModel *model = [BravoGiftWinningFlagViewModel modelWithJSON:attachment.data];
|
||||
if (model.roomId != roomID || model.uid != UID.integerValue || model.tip == nil) {
|
||||
if (model.roomId != roomID || model.uid != UID.integerValue || !model.tip) {
|
||||
return model;
|
||||
}
|
||||
|
||||
@@ -38,8 +38,27 @@
|
||||
flagView.model = model;
|
||||
flagView.alpha = 0;
|
||||
flagView.frame = CGRectMake(0, 0, kGetScaleWidth(274), kGetScaleWidth(216));
|
||||
flagView.center = CGPointMake(superView.center.x, kGetScaleWidth(216) + kGetScaleWidth(216)/2 - 40);
|
||||
|
||||
// 🔧 修复:重新计算位置,确保视图在屏幕可见范围内
|
||||
CGFloat viewWidth = kGetScaleWidth(274);
|
||||
CGFloat viewHeight = kGetScaleWidth(216);
|
||||
CGFloat screenWidth = KScreenWidth;
|
||||
CGFloat screenHeight = KScreenHeight;
|
||||
|
||||
// 计算安全的 Y 位置:屏幕高度的 40% 位置
|
||||
CGFloat safeY = screenHeight * 0.4;
|
||||
|
||||
// 确保视图不会超出屏幕边界
|
||||
CGFloat maxY = screenHeight - viewHeight/2 - 20; // 留20点边距
|
||||
CGFloat minY = viewHeight/2 + 20; // 留20点边距
|
||||
CGFloat finalY = MAX(minY, MIN(safeY, maxY));
|
||||
|
||||
flagView.center = CGPointMake(screenWidth/2, finalY);
|
||||
flagView.transform = CGAffineTransformMakeScale(0.1, 0.1);
|
||||
|
||||
NSLog(@"🎯 BravoGiftWinningFlagView: 位置计算 - screenSize: %.0fx%.0f, viewSize: %.0fx%.0f, center: (%.0f, %.0f)",
|
||||
screenWidth, screenHeight, viewWidth, viewHeight, flagView.center.x, flagView.center.y);
|
||||
|
||||
[superView addSubview:flagView];
|
||||
|
||||
// 使用弹簧动画执行放大动画,alpha从0变为1,带有弹性效果
|
||||
|
@@ -54,8 +54,27 @@
|
||||
winningFlagView.model = model;
|
||||
winningFlagView.alpha = 0;
|
||||
winningFlagView.frame = CGRectMake(0, 0, kGetScaleWidth(162), kGetScaleWidth(162));
|
||||
winningFlagView.center = CGPointMake(superView.center.x, kGetScaleWidth(163) + kGetScaleWidth(162)/2);
|
||||
|
||||
// 🔧 修复:重新计算位置,确保视图在屏幕可见范围内
|
||||
CGFloat viewWidth = kGetScaleWidth(162);
|
||||
CGFloat viewHeight = kGetScaleWidth(162);
|
||||
CGFloat screenWidth = KScreenWidth;
|
||||
CGFloat screenHeight = KScreenHeight;
|
||||
|
||||
// 计算安全的 Y 位置:屏幕高度的 35% 位置
|
||||
CGFloat safeY = screenHeight * 0.35;
|
||||
|
||||
// 确保视图不会超出屏幕边界
|
||||
CGFloat maxY = screenHeight - viewHeight/2 - 20; // 留20点边距
|
||||
CGFloat minY = viewHeight/2 + 20; // 留20点边距
|
||||
CGFloat finalY = MAX(minY, MIN(safeY, maxY));
|
||||
|
||||
winningFlagView.center = CGPointMake(screenWidth/2, finalY);
|
||||
winningFlagView.transform = CGAffineTransformMakeScale(0.1, 0.1);
|
||||
|
||||
NSLog(@"🎯 LuckyGiftWinningFlagView: 位置计算 - screenSize: %.0fx%.0f, viewSize: %.0fx%.0f, center: (%.0f, %.0f)",
|
||||
screenWidth, screenHeight, viewWidth, viewHeight, winningFlagView.center.x, winningFlagView.center.y);
|
||||
|
||||
[superView addSubview:winningFlagView];
|
||||
|
||||
// 使用弹簧动画执行放大动画,alpha从0变为1,带有弹性效果
|
||||
|
@@ -200,55 +200,29 @@ BannerSchedulerDelegate
|
||||
|
||||
- (void)removeItSelf {
|
||||
NSLog(@"<22><> RoomAnimationView: 开始销毁");
|
||||
|
||||
// 🔧 新增:取消所有动画,防止异步回调
|
||||
[self cancelAllAnimations];
|
||||
|
||||
// 移除广播代理
|
||||
[[NIMSDK sharedSDK].broadcastManager removeDelegate:self];
|
||||
|
||||
// 取消所有延迟执行
|
||||
[NSObject cancelPreviousPerformRequestsWithTarget:self];
|
||||
|
||||
// 清理所有 POP 动画
|
||||
[self pop_removeAllAnimations];
|
||||
|
||||
// 清理定时器
|
||||
if (_giftEffectTimer && !dispatch_source_testcancel(_giftEffectTimer)) {
|
||||
dispatch_source_cancel(_giftEffectTimer);
|
||||
_giftEffectTimer = nil;
|
||||
}
|
||||
|
||||
// 清理队列
|
||||
if (_giftEffectsQueue) {
|
||||
self.giftEffectsQueue = NULL;
|
||||
}
|
||||
|
||||
// <EFBFBD><EFBFBD> 新增:清理所有 banner 视图,防止 block 强引用
|
||||
[self cleanupAllSubviews];
|
||||
|
||||
// 🔧 新增:清理 BannerScheduler
|
||||
if (self.bannerScheduler) {
|
||||
NSLog(@"<22><> 清理 BannerScheduler");
|
||||
[self.bannerScheduler clearQueue];
|
||||
[self.bannerScheduler pause];
|
||||
self.bannerScheduler = nil;
|
||||
}
|
||||
|
||||
// 清理手势识别器
|
||||
[self cleanupGestureRecognizers];
|
||||
|
||||
// 清理缓存管理器
|
||||
[self cleanupCacheManagers];
|
||||
|
||||
// 移除通知监听
|
||||
[self removeNotificationObservers];
|
||||
|
||||
NSLog(@"<22><> RoomAnimationView: 销毁完成");
|
||||
[self smartDestroy];
|
||||
}
|
||||
|
||||
- (void)cancelAllAnimations {
|
||||
NSLog(@" 取消所有动画");
|
||||
NSLog(@"<EFBFBD><EFBFBD> 取消所有动画");
|
||||
|
||||
// <EFBFBD><EFBFBD> 新增:检查是否有正在播放的重要动画
|
||||
BOOL hasImportantAnimation = [self hasImportantAnimationPlaying];
|
||||
|
||||
if (hasImportantAnimation) {
|
||||
NSLog(@"⚠️ 检测到重要动画正在播放,延迟清理");
|
||||
// 延迟清理,给动画完成的时间
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
[self forceCancelAllAnimations];
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
[self forceCancelAllAnimations];
|
||||
}
|
||||
|
||||
- (void)forceCancelAllAnimations {
|
||||
NSLog(@"🔄 强制取消所有动画");
|
||||
|
||||
// 取消所有 POP 动画
|
||||
[self pop_removeAllAnimations];
|
||||
@@ -269,7 +243,25 @@ BannerSchedulerDelegate
|
||||
}
|
||||
|
||||
- (void)cleanupAllSubviews {
|
||||
NSLog(@" 清理所有子视图");
|
||||
NSLog(@"🔄 清理所有子视图");
|
||||
|
||||
// <EFBFBD><EFBFBD> 新增:检查是否有正在播放的重要动画
|
||||
BOOL hasImportantAnimation = [self hasImportantAnimationPlaying];
|
||||
|
||||
if (hasImportantAnimation) {
|
||||
NSLog(@"⚠️ 检测到重要动画正在播放,延迟清理子视图");
|
||||
// 延迟清理,给动画完成的时间
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
[self forceCleanupAllSubviews];
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
[self forceCleanupAllSubviews];
|
||||
}
|
||||
|
||||
- (void)forceCleanupAllSubviews {
|
||||
NSLog(@"<22><> 强制清理所有子视图");
|
||||
|
||||
// 清理所有容器的子视图
|
||||
NSArray *containers = @[self.bannerContainer, self.topContainer, self.middleContainer, self.bottomContainer];
|
||||
@@ -280,7 +272,7 @@ BannerSchedulerDelegate
|
||||
NSMutableArray *viewsToRemove = [NSMutableArray array];
|
||||
for (UIView *subview in container.subviews) {
|
||||
[viewsToRemove addObject:subview];
|
||||
NSLog(@" 标记移除视图: %@ (从容器: %@)", NSStringFromClass([subview class]), NSStringFromClass([container class]));
|
||||
NSLog(@"<EFBFBD><EFBFBD> 标记移除视图: %@ (从容器: %@)", NSStringFromClass([subview class]), NSStringFromClass([container class]));
|
||||
}
|
||||
|
||||
for (UIView *view in viewsToRemove) {
|
||||
@@ -289,7 +281,7 @@ BannerSchedulerDelegate
|
||||
|
||||
// 清理视图上的手势识别器
|
||||
if (view.gestureRecognizers.count > 0) {
|
||||
NSLog(@" 清理视图 %@ 上的 %lu 个手势识别器", NSStringFromClass([view class]), (unsigned long)view.gestureRecognizers.count);
|
||||
NSLog(@"<EFBFBD><EFBFBD> 清理视图 %@ 上的 %lu 个手势识别器", NSStringFromClass([view class]), (unsigned long)view.gestureRecognizers.count);
|
||||
for (UIGestureRecognizer *gesture in view.gestureRecognizers.copy) {
|
||||
[view removeGestureRecognizer:gesture];
|
||||
}
|
||||
@@ -4031,4 +4023,91 @@ BannerSchedulerDelegate
|
||||
}
|
||||
}
|
||||
|
||||
// 🔧 新增:检查重要动画状态
|
||||
- (BOOL)hasImportantAnimationPlaying {
|
||||
// 检查 topContainer 中是否有正在播放的重要动画
|
||||
for (UIView *subview in self.topContainer.subviews) {
|
||||
if ([subview isKindOfClass:[BravoGiftWinningFlagView class]] ||
|
||||
[subview isKindOfClass:[LuckyGiftWinningFlagView class]]) {
|
||||
NSLog(@"🎯 检测到重要动画正在播放: %@", NSStringFromClass([subview class]));
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查 middleContainer 中是否有正在播放的礼物动画
|
||||
for (UIView *subview in self.middleContainer.subviews) {
|
||||
if ([subview isKindOfClass:[SVGAImageView class]] ||
|
||||
[subview isKindOfClass:[VAPView class]] ||
|
||||
[subview isKindOfClass:[PAGView class]]) {
|
||||
NSLog(@"🎯 检测到礼物动画正在播放: %@", NSStringFromClass([subview class]));
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
// <EFBFBD><EFBFBD> 新增:智能销毁方法
|
||||
- (void)smartDestroy {
|
||||
// 检查是否有正在播放的重要动画
|
||||
BOOL hasImportantAnimation = [self hasImportantAnimationPlaying];
|
||||
|
||||
if (hasImportantAnimation) {
|
||||
NSLog(@"⚠️ 检测到重要动画正在播放,延迟销毁");
|
||||
// 延迟销毁,给动画完成的时间
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
[self forceDestroy];
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
[self forceDestroy];
|
||||
}
|
||||
|
||||
- (void)forceDestroy {
|
||||
NSLog(@"<22><> RoomAnimationView: 强制销毁");
|
||||
|
||||
// 移除广播代理
|
||||
[[NIMSDK sharedSDK].broadcastManager removeDelegate:self];
|
||||
|
||||
// 取消所有延迟执行
|
||||
[NSObject cancelPreviousPerformRequestsWithTarget:self];
|
||||
|
||||
// 清理所有 POP 动画
|
||||
[self pop_removeAllAnimations];
|
||||
|
||||
// 清理定时器
|
||||
if (_giftEffectTimer && !dispatch_source_testcancel(_giftEffectTimer)) {
|
||||
dispatch_source_cancel(_giftEffectTimer);
|
||||
_giftEffectTimer = nil;
|
||||
}
|
||||
|
||||
// 清理队列
|
||||
if (_giftEffectsQueue) {
|
||||
self.giftEffectsQueue = NULL;
|
||||
}
|
||||
|
||||
// 清理所有 banner 视图,防止 block 强引用
|
||||
[self cleanupAllSubviews];
|
||||
|
||||
// 清理 BannerScheduler
|
||||
if (self.bannerScheduler) {
|
||||
NSLog(@"<22><> 清理 BannerScheduler");
|
||||
[self.bannerScheduler clearQueue];
|
||||
[self.bannerScheduler pause];
|
||||
self.bannerScheduler = nil;
|
||||
}
|
||||
|
||||
// 清理手势识别器
|
||||
[self cleanupGestureRecognizers];
|
||||
|
||||
// 清理缓存管理器
|
||||
[self cleanupCacheManagers];
|
||||
|
||||
// 移除通知监听
|
||||
[self removeNotificationObservers];
|
||||
|
||||
NSLog(@"<22><> RoomAnimationView: 销毁完成");
|
||||
}
|
||||
|
||||
@end
|
||||
|
@@ -604,7 +604,6 @@ XPCandyTreeInsufficientBalanceViewDelegate>
|
||||
self.view.backgroundColor = [UIColor darkGrayColor];
|
||||
[self.view addSubview:self.backContainerView];
|
||||
[self.view addSubview:self.littleGameView];
|
||||
[self.view addSubview:self.stageView];
|
||||
[self.view addSubview:self.messageContainerView];
|
||||
|
||||
[self.view addSubview:self.quickMessageContainerView];
|
||||
@@ -660,14 +659,8 @@ XPCandyTreeInsufficientBalanceViewDelegate>
|
||||
make.height.mas_equalTo(kNavigationHeight);
|
||||
}];
|
||||
|
||||
[self.stageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.leading.trailing.mas_equalTo(self.view);
|
||||
make.top.mas_equalTo(self.roomHeaderView.mas_bottom);
|
||||
make.height.mas_equalTo(self.stageView.hightForStageView);
|
||||
}];
|
||||
|
||||
[self.messageContainerView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(self.stageView.mas_bottom);
|
||||
make.top.equalTo(self.roomHeaderView.mas_bottom);
|
||||
make.bottom.equalTo(self.quickMessageContainerView.mas_top).offset(-5);
|
||||
make.leading.equalTo(self.view);
|
||||
make.trailing.equalTo(self.sideMenu.mas_leading).offset(-10);
|
||||
@@ -3195,9 +3188,16 @@ XPCandyTreeInsufficientBalanceViewDelegate>
|
||||
}
|
||||
|
||||
- (StageView *)stageView {
|
||||
// 🔧 修改:如果 StageViewManager 已初始化,返回其管理的 stageView
|
||||
if (self.stageViewManager && self.stageViewManager.currentStageView) {
|
||||
return self.stageViewManager.currentStageView;
|
||||
}
|
||||
|
||||
// 🔧 降级:只有在 StageViewManager 不可用时才创建默认的 SocialStageView
|
||||
if (!_stageView) {
|
||||
_stageView = [[SocialStageView alloc] initWithDelegate:self];
|
||||
_stageView.alpha = 0;
|
||||
NSLog(@"⚠️ 使用降级 stageView: SocialStageView");
|
||||
}
|
||||
return _stageView;
|
||||
}
|
||||
|
Reference in New Issue
Block a user