优化 PIGiftBravoGiftBroadcastView 动画逻辑,调整动画时序和状态管理,增加数据源检查,确保动画流畅性和稳定性。同时,添加详细日志输出以便于调试和监控。

This commit is contained in:
edwinQQQ
2025-08-25 15:08:24 +08:00
parent 3df04b9b90
commit c5cde5b5c4
7 changed files with 446 additions and 57 deletions

View File

@@ -1 +1 @@
57817
56756

View File

@@ -376,24 +376,27 @@
if (message.session.sessionType == NIMSessionTypeChatroom) {
NSString *sessionId = message.session.sessionId;
if ([sessionId isEqualToString:self.currentPublicRoomId]) {
NIMMessageChatroomExtension *messageExt = (NIMMessageChatroomExtension *)message.messageExt;
AttachmentModel *attachment;
if (message.messageType == NIMMessageTypeCustom) {
NIMCustomObject *obj = (NIMCustomObject *) message.messageObject;
attachment = (AttachmentModel *) obj.attachment;
if (attachment) {
switch (attachment.first) {
case CustomMessageType_Super_Gift:
[self handleFirst_106:attachment
message:message];
break;
default:
break;
}
if (attachment.first > 0 && attachment.second >0) {
[self handleMessageWithAttachmentAndFirstSecond:message];
}
// if (attachment) {
// switch (attachment.first) {
// case CustomMessageType_Super_Gift:
// [self handleFirst_106:attachment
// message:message];
// break;
// default:
// break;
// }
// }
}
// NIMMessageChatroomExtension *messageExt = (NIMMessageChatroomExtension *)message.messageExt;
// NSLog(@"PublicRoomManager: 收到公共房间消息: %@\n%@",
// message.rawAttachContent,
// messageExt.roomExt);
@@ -402,8 +405,15 @@
}
}
- (void)handleMessageWithAttachmentAndFirstSecond:(NIMMessage *)message {
}
- (void)handleFirst_106:(AttachmentModel *)attachment
message:(NIMMessage *)message {
// allRoomMsg
//
if (![XPSkillCardPlayerManager shareInstance].isInRoom) {
NSLog(@"PublicRoomManager: 用户未在房间中,跳过消息转发");

View File

@@ -799,6 +799,9 @@ BannerSchedulerDelegate
NSLog(@"🔄 BravoGiftBannerView complete 回调被调用");
self.isRoomBannerV2Displaying = NO;
[self.bannerScheduler markBannerFinished];
// 🔧
[self ensureBannerGestureContainersEnabled];
} exitCurrentRoom:^{
@kStrongify(self);
if (!self || !self.superview) {
@@ -826,6 +829,9 @@ BannerSchedulerDelegate
NSLog(@"🔄 LuckyPackageBannerView complete 回调被调用");
self.isRoomBannerV2Displaying = NO;
[self.bannerScheduler markBannerFinished];
// 🔧
[self ensureBannerGestureContainersEnabled];
} exitCurrentRoom:^{
@kStrongify(self);
[self.hostDelegate exitRoom];
@@ -851,6 +857,9 @@ BannerSchedulerDelegate
NSLog(@"🔄 RoomHighValueGiftBannerAnimation complete 回调被调用");
self.isRoomBannerV2Displaying = NO;
[self.bannerScheduler markBannerFinished];
// 🔧
[self ensureBannerGestureContainersEnabled];
}];
}
@@ -866,6 +875,9 @@ BannerSchedulerDelegate
@kStrongify(self);
self.isRoomBannerV2Displaying = NO;
[self.bannerScheduler markBannerFinished];
// 🔧
[self ensureBannerGestureContainersEnabled];
}];
}
@@ -878,6 +890,9 @@ BannerSchedulerDelegate
NSLog(@"🔄 CPGiftBanner complete 回调被调用");
self.isRoomBannerV2Displaying = NO;
[self.bannerScheduler markBannerFinished];
// 🔧
[self ensureBannerGestureContainersEnabled];
}];
}
@@ -889,6 +904,9 @@ BannerSchedulerDelegate
@kStrongify(self);
self.isRoomBannerV2Displaying = NO;
[self.bannerScheduler markBannerFinished];
// 🔧
[self ensureBannerGestureContainersEnabled];
}];
}
@@ -1052,6 +1070,9 @@ BannerSchedulerDelegate
NSLog(@"🔄 LuckyGiftWinningBannerView complete 回调被调用");
self.isRoomBannerV2Displaying = NO;
[self.bannerScheduler markBannerFinished];
// 🔧
[self ensureBannerGestureContainersEnabled];
} exitCurrentRoom:^{
@kStrongify(self);
[self.hostDelegate exitRoom];
@@ -1091,6 +1112,9 @@ BannerSchedulerDelegate
NSLog(@"🔄 GameUniversalBannerView complete 回调被调用");
self.isRoomBannerV2Displaying = NO;
[self.bannerScheduler markBannerFinished];
// 🔧
[self ensureBannerGestureContainersEnabled];
} goToGame:^(NSInteger gameID) {
@kStrongify(self);
NSArray *baishunList = [self.hostDelegate getPlayList];
@@ -2426,7 +2450,28 @@ BannerSchedulerDelegate
- (void)handleBannerTap:(UITapGestureRecognizer *)tapGesture {
CGPoint tapPoint = [tapGesture locationInView:self.bannerContainer];
// banner tap
// 🔧 banner
BOOL hasVisibleBanner = NO;
for (UIView *subview in self.bannerContainer.subviews) {
if (!subview.hidden && subview.alpha > 0.01) {
hasVisibleBanner = YES;
break;
}
}
// banner
if (!hasVisibleBanner) {
NSLog(@"🎯 没有可见 banner直接转发点击事件到下层");
self.savedTapPoint = tapPoint;
self.hasSavedTapPoint = YES;
CGPoint screenPoint = [self.bannerContainer convertPoint:tapPoint toView:nil];
[[NSNotificationCenter defaultCenter] postNotificationName:@"BannerTapToFunctionContainer"
object:nil
userInfo:@{@"point": [NSValue valueWithCGPoint:screenPoint]}];
return;
}
// banner
if ([self isPointInBannerInteractiveArea:tapPoint]) {
// banner banner
NSLog(@"🎯 Banner tap 位置在可交互区域banner 将处理此事件");
@@ -2440,7 +2485,6 @@ BannerSchedulerDelegate
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]}];
@@ -3786,6 +3830,9 @@ BannerSchedulerDelegate
- (void)bannerSchedulerDidFinishPlaying:(BannerScheduler *)scheduler {
// Banner
NSLog(@"🔄 BannerScheduler: Banner 播放完成");
// 🔧
[self ensureBannerGestureContainersEnabled];
}
- (void)bannerScheduler:(BannerScheduler *)scheduler didStartPlayingBanner:(id)banner {
@@ -3904,6 +3951,29 @@ BannerSchedulerDelegate
NSLog(@"🎯 RoomAnimationView: Banner 手势容器已恢复显示(非小游戏模式)");
}
// 🔧
- (void)ensureBannerGestureContainersEnabled {
//
if (self.bannerSwipeGestureContainer.hidden ||
self.bannerLeftTapGestureContainer.hidden ||
self.bannerRightTapGestureContainer.hidden) {
NSLog(@"🔧 检测到手势容器被隐藏,重新激活");
[self restoreBannerGestureNormalMode];
}
//
if (!self.bannerSwipeGestureContainer.userInteractionEnabled ||
!self.bannerLeftTapGestureContainer.userInteractionEnabled ||
!self.bannerRightTapGestureContainer.userInteractionEnabled) {
NSLog(@"🔧 检测到手势容器用户交互被禁用,重新启用");
self.bannerSwipeGestureContainer.userInteractionEnabled = YES;
self.bannerLeftTapGestureContainer.userInteractionEnabled = YES;
self.bannerRightTapGestureContainer.userInteractionEnabled = YES;
}
}
@end

View File

@@ -133,8 +133,10 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey";
/// tag datasource
- (void)updateAllDataSource:(NSArray *)datas {
if (!datas || datas.count == 0) {
self.datasource_chat = @[].mutableCopy;
self.datasource_gift = @[].mutableCopy;
//
[self.datasource_chat removeAllObjects];
[self.datasource_gift removeAllObjects];
//
datas = self.datasource;
}
@@ -152,6 +154,8 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey";
case CustomMessageType_Treasure_Fairy:
[self.datasource_gift addObject:model];
break;
default:
break;
}
}
}
@@ -178,8 +182,6 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey";
- (void)appendAndScrollToAtUser {
// 1. incomingMessages
if (self.incomingMessages.count < 1) {
NSInteger rows = self.datasource.count;
// 2. locationArray
if (self.locationArray.count == 0) {
[self scrollToBottomWithTipsHidden:YES];
@@ -193,15 +195,22 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey";
return;
}
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];
if (rows > indexPath.row) {
[self.messageTableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
if (rows == indexPath.row + 1) {
self.messageTipsBtn.hidden = YES;
self.isPending = NO;
}
} else {
// datasource
NSInteger convertedIndex = [self convertDataSourceIndexToCurrentDisplayIndex:index];
if (convertedIndex == NSNotFound) {
[self scrollToBottomWithTipsHidden:YES];
} else {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:convertedIndex inSection:0];
NSInteger currentRows = [self getCurrentDataSourceCount];
if (currentRows > indexPath.row) {
[self.messageTableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
if (currentRows == indexPath.row + 1) {
self.messageTipsBtn.hidden = YES;
self.isPending = NO;
}
} else {
[self scrollToBottomWithTipsHidden:YES];
}
}
[self safelyRemoveLocationAtIndex:0];
@@ -217,8 +226,10 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey";
needReloadData = YES; //
}
// 5.
NSMutableArray *indexPaths = @[].mutableCopy;
// 5.
NSInteger currentRows = [self getCurrentDataSourceCount];
// 6.
NSMutableArray *tempNewDatas = @[].mutableCopy;
for (id item in self.incomingMessages) {
XPMessageInfoModel *model = [self parseMessage:item];
@@ -226,18 +237,32 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey";
[tempNewDatas addObject:model];
[self.datasource addObject:model];
[indexPaths addObject:[NSIndexPath indexPathForRow:self.datasource.count - 1 inSection:0]];
[self processAtMentionsForMessage:item];
}
[self updateAllDataSource:tempNewDatas];
[self.incomingMessages removeAllObjects];
// 使 reloadData使
// 7. UITableView
if (needReloadData) {
[self.messageTableView reloadData];
} else if (indexPaths.count > 0) {
[self.messageTableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
} else if (tempNewDatas.count > 0) {
//
NSInteger expectedRows = [self getCurrentDataSourceCount];
if (expectedRows != [self.messageTableView numberOfRowsInSection:0]) {
[self.messageTableView reloadData];
} else {
// indexPath使
NSMutableArray *indexPaths = @[].mutableCopy;
NSInteger startIndex = currentRows;
if (startIndex >= 0 && startIndex <= [self.messageTableView numberOfRowsInSection:0]) {
for (NSInteger i = 0; i < tempNewDatas.count; i++) {
[indexPaths addObject:[NSIndexPath indexPathForRow:startIndex + i inSection:0]];
}
[self.messageTableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
} else {
[self.messageTableView reloadData];
}
}
}
// 6.
@@ -245,9 +270,11 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey";
}
- (void)scrollToBottomWithTipsHidden:(BOOL)hidden {
NSInteger rows = self.datasource.count;
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:(rows - 1) inSection:0];
[self.messageTableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
NSInteger rows = [self getCurrentDataSourceCount];
if (rows > 0) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:(rows - 1) inSection:0];
[self.messageTableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
self.messageTipsBtn.hidden = hidden;
self.isPending = NO;
self.atCount = 0;
@@ -296,9 +323,32 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey";
- (void)safelyRemoveMessages:(NSInteger)count {
if (self.datasource.count >= count) {
//
NSIndexSet *set = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, count)];
NSArray *removedMessages = [self.datasource objectsAtIndexes:set];
//
[self.datasource removeObjectsAtIndexes:set];
[self updateAllDataSource:nil];
//
for (XPMessageInfoModel *removedModel in removedMessages) {
switch (removedModel.first) {
case NIMMessageTypeText:
case CustomMessageType_Face:
[self.datasource_chat removeObject:removedModel];
break;
case CustomMessageType_Gift:
case CustomMessageType_RoomBoom:
case CustomMessageType_Candy_Tree:
case CustomMessageType_Super_Gift:
case CustomMessageType_AllMicroSend:
case CustomMessageType_Treasure_Fairy:
[self.datasource_gift removeObject:removedModel];
break;
default:
break;
}
}
// locationArray
NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet];
@@ -336,18 +386,81 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey";
}
}
- (NSInteger)getCurrentDataSourceCount {
NSInteger count = 0;
switch (self.displayType) {
case 1:
count = self.datasource.count;
break;
case 2:
count = self.datasource_chat.count;
break;
case 3:
count = self.datasource_gift.count;
break;
default:
count = self.datasource.count;
break;
}
//
return MAX(0, count);
}
- (NSInteger)convertDataSourceIndexToCurrentDisplayIndex:(NSInteger)dataSourceIndex {
if (self.displayType == 1) {
return dataSourceIndex;
}
if (dataSourceIndex >= self.datasource.count) {
return NSNotFound;
}
XPMessageInfoModel *targetModel = [self.datasource objectAtIndex:dataSourceIndex];
if (!targetModel) {
return NSNotFound;
}
NSArray *currentDataSource = nil;
switch (self.displayType) {
case 2:
currentDataSource = self.datasource_chat;
break;
case 3:
currentDataSource = self.datasource_gift;
break;
default:
return dataSourceIndex;
}
//
for (NSInteger i = 0; i < currentDataSource.count; i++) {
XPMessageInfoModel *model = [currentDataSource objectAtIndex:i];
if ([model isEqual:targetModel]) {
return i;
}
}
return NSNotFound;
}
- (void)scrollToFirstLocationOrBottom {
NSInteger rows = self.datasource.count;
if (self.locationArray.count == 0) {
[self scrollToBottomWithTipsHidden:YES];
return;
}
NSInteger index = [self safeGetIndexFromLocationArrayAt:0];
if (index == NSNotFound || index >= rows) {
if (index == NSNotFound) {
[self scrollToBottomWithTipsHidden:YES];
return;
}
// datasource
NSInteger convertedIndex = [self convertDataSourceIndexToCurrentDisplayIndex:index];
if (convertedIndex == NSNotFound) {
[self scrollToBottomWithTipsHidden:YES];
} else {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:convertedIndex inSection:0];
[self.messageTableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
[self safelyRemoveLocationAtIndex:0];
}
@@ -473,14 +586,15 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey";
BOOL needReloadData = NO;
if (self.datasource.count > kRoomMessageMaxLength) {
NSIndexSet *set = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, kRoomMessageMaxLength/2)];
NSArray *needRemoveMsgArray = [self.datasource objectsAtIndexes:set];
[self.datasource removeObjectsInArray:needRemoveMsgArray];
NSInteger removedCount = kRoomMessageMaxLength / 2;
[self safelyRemoveMessages:removedCount];
needReloadData = YES; //
}
//
NSInteger currentRows = [self getCurrentDataSourceCount];
NSMutableArray *tempArray = @[].mutableCopy;
NSMutableArray *indexPaths = @[].mutableCopy;
@kWeakify(self);
[self.incomingMessages enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
@kStrongify(self);
@@ -493,7 +607,6 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey";
if (model) {
[tempArray addObject:model];
[self.datasource addObject:model];
[indexPaths addObject:[NSIndexPath indexPathForRow:self.datasource.count - 1 inSection:0]];
}
}];
@@ -504,8 +617,24 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey";
// 使 reloadData使
if (needReloadData) {
[self.messageTableView reloadData];
} else if (indexPaths.count > 0) {
[self.messageTableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
} else if (tempArray.count > 0) {
//
NSInteger expectedRows = [self getCurrentDataSourceCount];
if (expectedRows != [self.messageTableView numberOfRowsInSection:0]) {
[self.messageTableView reloadData];
} else {
// indexPath使
NSMutableArray *indexPaths = @[].mutableCopy;
NSInteger startIndex = currentRows;
if (startIndex >= 0 && startIndex <= [self.messageTableView numberOfRowsInSection:0]) {
for (NSInteger i = 0; i < tempArray.count; i++) {
[indexPaths addObject:[NSIndexPath indexPathForRow:startIndex + i inSection:0]];
}
[self.messageTableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
} else {
[self.messageTableView reloadData];
}
}
}
//
@@ -1340,21 +1469,23 @@ NSString * const kRoomShowTopicKey = @"kRoomShowTopicKey";
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSInteger count = 0;
switch (self.displayType) {
case 1:
return self.datasource.count;
count = self.datasource.count;
break;
case 2:
return self.datasource_chat.count;
count = self.datasource_chat.count;
break;
case 3:
return self.datasource_gift.count;
count = self.datasource_gift.count;
break;
default:
return self.datasource.count;
count = self.datasource.count;
break;
}
//
return MAX(0, count);
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

View File

@@ -161,6 +161,13 @@
self.isAnimating = NO;
self.shouldStopAnimation = NO;
//
if (self.source.count < 2) {
NSLog(@"⚠️ PIGiftBravoGiftBroadcastView: 数据源不足 (%lu个),动画可能过快", (unsigned long)self.source.count);
} else {
NSLog(@"✅ PIGiftBravoGiftBroadcastView: 数据源正常 (%lu个)", (unsigned long)self.source.count);
}
@kWeakify(self);
[self.source enumerateObjectsUsingBlock:^(BravoGiftTabInfomationModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
@kStrongify(self);
@@ -176,10 +183,13 @@
- (void)startLoop {
if (self.isAnimating || self.labels.count == 0 || self.shouldStopAnimation) {
NSLog(@"🚫 PIGiftBravoGiftBroadcastView: 动画启动被阻止 - isAnimating:%d, labelsCount:%lu, shouldStop:%d",
self.isAnimating, (unsigned long)self.labels.count, self.shouldStopAnimation);
return;
}
self.isAnimating = YES;
NSLog(@"🎬 PIGiftBravoGiftBroadcastView: 开始动画循环");
[self playCurrentAnimation];
}
@@ -187,21 +197,33 @@
- (void)startAnimation {
if (self.shouldStopAnimation) {
self.shouldStopAnimation = NO;
NSLog(@"🔄 PIGiftBravoGiftBroadcastView: 重置停止标志,重新开始动画");
}
if (self.labels.count > 0) {
[self startLoop];
} else {
NSLog(@"⚠️ PIGiftBravoGiftBroadcastView: 无法开始动画labels为空");
}
}
//
- (void)stopAnimation {
NSLog(@"⏹️ PIGiftBravoGiftBroadcastView: 停止动画");
[self endloop];
}
- (void)playCurrentAnimation {
//
if (self.shouldStopAnimation) {
self.isAnimating = NO;
NSLog(@"🚫 PIGiftBravoGiftBroadcastView: 动画被停止标志阻止");
return;
}
//
if (self.container.subviews.count > 0) {
NSLog(@"⚠️ PIGiftBravoGiftBroadcastView: 容器中已有视图,跳过当前动画");
return;
}
@@ -209,9 +231,12 @@
PIGiftBravoGiftBroadcastItemView *item = [self.labels xpSafeObjectAtIndex:self.index];
if (!item) {
self.isAnimating = NO;
NSLog(@"❌ PIGiftBravoGiftBroadcastView: 无法获取当前索引(%ld)的视图", (long)self.index);
return;
}
NSLog(@"🎭 PIGiftBravoGiftBroadcastView: 播放第%ld个动画项", (long)self.index);
//
item.frame = CGRectMake(KScreenWidth, 2, KScreenWidth - 25 - 42, 26);
//
@@ -226,11 +251,12 @@
if (!finished || self.shouldStopAnimation) {
[item removeFromSuperview];
self.isAnimating = NO;
NSLog(@"❌ PIGiftBravoGiftBroadcastView: 入场动画被中断");
return;
}
// 2
[UIView animateWithDuration:0.5 delay:2.0 options:UIViewAnimationOptionCurveEaseIn animations:^{
// 23
[UIView animateWithDuration:0.5 delay:3.0 options:UIViewAnimationOptionCurveEaseIn animations:^{
item.frame = CGRectMake(-KScreenWidth, 2, KScreenWidth - 25 - 42, 26);
} completion:^(BOOL finished) {
@kStrongify(self);
@@ -239,6 +265,7 @@
if (self.shouldStopAnimation) {
self.isAnimating = NO;
NSLog(@"⏹️ PIGiftBravoGiftBroadcastView: 出场动画被停止");
return;
}
@@ -246,10 +273,12 @@
self.index += 1;
if (self.index >= self.labels.count) {
self.index = 0;
NSLog(@"🔄 PIGiftBravoGiftBroadcastView: 动画循环重置到开始");
}
// 使
self.animationTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(scheduleNextAnimation) userInfo:nil repeats:NO];
// 使0.10.5
self.animationTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(scheduleNextAnimation) userInfo:nil repeats:NO];
NSLog(@"⏰ PIGiftBravoGiftBroadcastView: 安排下一个动画延迟0.5秒");
}];
}];
}
@@ -260,9 +289,11 @@
if (self.shouldStopAnimation) {
self.isAnimating = NO;
NSLog(@"🚫 PIGiftBravoGiftBroadcastView: 定时器回调被停止标志阻止");
return;
}
NSLog(@"▶️ PIGiftBravoGiftBroadcastView: 定时器触发下一个动画");
[self playCurrentAnimation];
}
@@ -271,6 +302,8 @@
self.shouldStopAnimation = YES;
self.isAnimating = NO;
NSLog(@"🛑 PIGiftBravoGiftBroadcastView: 结束动画循环");
//
if (self.animationTimer) {
[self.animationTimer invalidate];

View File

@@ -195,6 +195,9 @@ XPCandyTreeInsufficientBalanceViewDelegate>
/// 10
@property(nonatomic,strong) NSTimer *upMicAskTimer;
/// 🔧 block
@property(nonatomic,strong) id<NSObject> exchangeRoomAnimationViewObserver;
@end
@implementation XPRoomViewController
@@ -310,6 +313,12 @@ XPCandyTreeInsufficientBalanceViewDelegate>
[[RoomBoomManager sharedManager] removeEventListenerForTarget:self];
// 🔧 block
if (self.exchangeRoomAnimationViewObserver) {
[[NSNotificationCenter defaultCenter] removeObserver:self.exchangeRoomAnimationViewObserver];
self.exchangeRoomAnimationViewObserver = nil;
}
[[NSNotificationCenter defaultCenter] removeObserver:self];
// 🔧 RoomAnimationView
@@ -451,7 +460,8 @@ XPCandyTreeInsufficientBalanceViewDelegate>
object:nil];
@kWeakify(self);
[[NSNotificationCenter defaultCenter] addObserverForName:@"kExchangeRoomAnimationViewAndGameViewIndex"
// 🔧 block
self.exchangeRoomAnimationViewObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"kExchangeRoomAnimationViewAndGameViewIndex"
object:nil
queue:NSOperationQueue.mainQueue
usingBlock:^(NSNotification * _Nonnull notification) {
@@ -1929,6 +1939,11 @@ XPCandyTreeInsufficientBalanceViewDelegate>
NSLog(@"[Recv] --- Message Raw Attach Content: %@, %@, %ld", @(message.senderClientType), message.rawAttachContent, (long)message.messageType);
if ([message.rawAttachContent containsString:@"\"allRoomMsg\":1"]) {
NSLog(@"[Recv] --- 拦截旧的全房间消息");
continue;
}
if (message.messageType == NIMMessageTypeNotification) {
[self handleNIMNotificationTypeMessage:message];
} else if (message.messageType == NIMMessageTypeCustom) {

View File

@@ -0,0 +1,130 @@
# PIGiftBravoGiftBroadcastView 动画速度修复
## 问题描述
`PIGiftBravoGiftBroadcastView` 中内容切换的动画变得非常快,影响用户体验。
## 问题分析
### 1. 动画时序问题
- **原有时序**
- 入场动画0.5秒
- 停留时间2.0秒延迟
- 出场动画0.5秒
- 下一个动画间隔0.1秒
- **问题**:间隔时间过短,导致动画切换过快
### 2. 状态管理问题
- 缺少严格的状态检查
- 可能存在多个动画同时运行的情况
- 状态同步不够完善
### 3. 数据源问题
- 没有对数据源进行验证
- 数据源不足时可能导致动画异常
## 解决方案
### 1. 调整动画时序
- **停留时间**从2秒增加到3秒
- **间隔时间**从0.1秒增加到0.5秒
- **总周期**从3.1秒增加到4.5秒
### 2. 优化状态管理
- 添加更严格的状态检查
- 确保只有一个动画在运行
- 防止容器中同时存在多个视图
### 3. 添加数据源检查
- 在setupUI中验证数据源数量
- 添加详细的日志输出便于调试
## 修改内容
### 文件:`PIGiftBravoGiftBroadcastView.m`
#### 1. setupUI方法
```objc
// 检查数据源
if (self.source.count < 2) {
NSLog(@"⚠️ PIGiftBravoGiftBroadcastView: 数据源不足 (%lu个),动画可能过快", (unsigned long)self.source.count);
} else {
NSLog(@"✅ PIGiftBravoGiftBroadcastView: 数据源正常 (%lu个)", (unsigned long)self.source.count);
}
```
#### 2. playCurrentAnimation方法
```objc
// 更严格的状态检查
if (self.shouldStopAnimation) {
self.isAnimating = NO;
NSLog(@"🚫 PIGiftBravoGiftBroadcastView: 动画被停止标志阻止");
return;
}
// 确保只有一个动画在运行
if (self.container.subviews.count > 0) {
NSLog(@"⚠️ PIGiftBravoGiftBroadcastView: 容器中已有视图,跳过当前动画");
return;
}
// 停留时间从2秒增加到3秒
[UIView animateWithDuration:0.5 delay:3.0 options:UIViewAnimationOptionCurveEaseIn animations:^{
item.frame = CGRectMake(-KScreenWidth, 2, KScreenWidth - 25 - 42, 26);
} completion:^(BOOL finished) {
// 使用定时器延迟下一个动画从0.1秒增加到0.5秒
self.animationTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(scheduleNextAnimation) userInfo:nil repeats:NO];
NSLog(@"⏰ PIGiftBravoGiftBroadcastView: 安排下一个动画延迟0.5秒");
}];
```
#### 3. 添加详细日志
- 动画启动/停止状态
- 数据源验证结果
- 动画播放进度
- 状态变化追踪
## 预期效果
### 1. 动画速度改善
- 动画切换更加平滑自然
- 用户有足够时间阅读内容
- 减少视觉疲劳
### 2. 稳定性提升
- 防止多个动画同时运行
- 更好的状态管理
- 减少异常情况
### 3. 调试便利性
- 详细的日志输出
- 便于问题定位
- 性能监控
## 测试建议
### 1. 功能测试
- 验证动画时序是否正确
- 检查状态管理是否正常
- 确认数据源检查是否有效
### 2. 性能测试
- 监控内存使用情况
- 检查CPU占用率
- 验证动画流畅度
### 3. 边界测试
- 数据源为空的情况
- 快速切换场景的情况
- 内存压力下的表现
## 注意事项
1. **向后兼容**修改保持了原有的API接口不变
2. **性能影响**增加了日志输出在Release版本中可以考虑移除
3. **配置灵活**:动画时间可以通过常量定义,便于后续调整
## 修改时间
2025年1月27日
## 修改人员
AI Assistant