修改bug

This commit is contained in:
2026-01-27 17:03:16 +08:00
parent 2b749cd2b0
commit e67bc37571
4 changed files with 134 additions and 35 deletions

View File

@@ -73,6 +73,7 @@
self.messageLabel.numberOfLines = 0; self.messageLabel.numberOfLines = 0;
self.messageLabel.font = [UIFont systemFontOfSize:16]; self.messageLabel.font = [UIFont systemFontOfSize:16];
self.messageLabel.textColor = [UIColor whiteColor]; self.messageLabel.textColor = [UIColor whiteColor];
self.messageLabel.lineBreakMode = NSLineBreakByWordWrapping;
// preferredMaxLayoutWidth AutoLayout // preferredMaxLayoutWidth AutoLayout
CGFloat maxWidth = [UIScreen mainScreen].bounds.size.width * 0.75 - 16 - 24; CGFloat maxWidth = [UIScreen mainScreen].bounds.size.width * 0.75 - 16 - 24;
self.messageLabel.preferredMaxLayoutWidth = maxWidth; self.messageLabel.preferredMaxLayoutWidth = maxWidth;
@@ -94,20 +95,22 @@
make.center.equalTo(self.voiceButton); make.center.equalTo(self.voiceButton);
}]; }];
// bubbleView // bubbleView
[self.bubbleView mas_makeConstraints:^(MASConstraintMaker *make) { [self.bubbleView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.voiceButton.mas_bottom).offset(4); make.top.equalTo(self.voiceButton.mas_bottom).offset(4);
make.bottom.equalTo(self.contentView).offset(-4); make.bottom.equalTo(self.contentView).offset(-4).priority(999); //
make.left.equalTo(self.contentView).offset(16); make.left.equalTo(self.contentView).offset(16);
make.width.lessThanOrEqualTo(self.contentView).multipliedBy(0.75); make.width.lessThanOrEqualTo(self.contentView).multipliedBy(0.75);
}]; }];
// messageLabel // messageLabel AutoLayout bubbleView
[self.messageLabel mas_makeConstraints:^(MASConstraintMaker *make) { [self.messageLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.bubbleView).offset(10); make.top.equalTo(self.bubbleView).offset(10);
make.bottom.equalTo(self.bubbleView).offset(-10); make.bottom.equalTo(self.bubbleView).offset(-10).priority(999); //
make.left.equalTo(self.bubbleView).offset(12); make.left.equalTo(self.bubbleView).offset(12);
make.right.equalTo(self.bubbleView).offset(-12); make.right.equalTo(self.bubbleView).offset(-12);
// messageLabel 0
make.height.greaterThanOrEqualTo(@20);
}]; }];
} }
@@ -127,10 +130,18 @@
NSLog(@"[KBChatAssistantMessageCell] 启动新的打字机效果"); NSLog(@"[KBChatAssistantMessageCell] 启动新的打字机效果");
[self startTypewriterEffectWithText:message.text]; [self startTypewriterEffectWithText:message.text];
} else { } else {
// // attributedText使 text
NSLog(@"[KBChatAssistantMessageCell] 直接显示完整文本needsTypewriter: %d, isComplete: %d", NSLog(@"[KBChatAssistantMessageCell] 直接显示完整文本needsTypewriter: %d, isComplete: %d",
message.needsTypewriterEffect, message.isComplete); message.needsTypewriterEffect, message.isComplete);
self.messageLabel.text = message.text; self.messageLabel.attributedText = nil; // attributedText
self.messageLabel.text = message.text; //
//
[self.contentView setNeedsLayout];
[self.contentView layoutIfNeeded];
NSLog(@"[KBChatAssistantMessageCell] 直接显示后 Label frame: %@",
NSStringFromCGRect(self.messageLabel.frame));
} }
// 0 // 0
@@ -191,30 +202,33 @@
self.fullText = text; self.fullText = text;
self.currentCharIndex = 0; self.currentCharIndex = 0;
// //
self.messageLabel.text = text; self.messageLabel.text = text;
// // Cell
[self.messageLabel setNeedsLayout];
[self.bubbleView setNeedsLayout];
[self.contentView setNeedsLayout]; [self.contentView setNeedsLayout];
[self layoutIfNeeded]; [self.contentView layoutIfNeeded];
NSLog(@"[KBChatAssistantMessageCell] 布局后 Label frame: %@", NSStringFromCGRect(self.messageLabel.frame)); NSLog(@"[KBChatAssistantMessageCell] 布局后 Label frame: %@, bubbleView frame: %@",
NSStringFromCGRect(self.messageLabel.frame),
NSStringFromCGRect(self.bubbleView.frame));
// 使 NSAttributedString // attributedText
//
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:text];
[attributedText addAttribute:NSForegroundColorAttributeName
value:[UIColor clearColor]
range:NSMakeRange(0, text.length)];
[attributedText addAttribute:NSFontAttributeName
value:self.messageLabel.font
range:NSMakeRange(0, text.length)];
self.messageLabel.attributedText = attributedText;
// 线
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
// 使 NSAttributedString
//
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:text];
[attributedText addAttribute:NSForegroundColorAttributeName
value:[UIColor clearColor]
range:NSMakeRange(0, text.length)];
[attributedText addAttribute:NSFontAttributeName
value:self.messageLabel.font
range:NSMakeRange(0, text.length)];
self.messageLabel.attributedText = attributedText;
// attributedText
[self.contentView layoutIfNeeded];
// 0.03 // 0.03
self.typewriterTimer = [NSTimer scheduledTimerWithTimeInterval:0.03 self.typewriterTimer = [NSTimer scheduledTimerWithTimeInterval:0.03
target:self target:self

View File

@@ -64,9 +64,16 @@ static const NSTimeInterval kTimestampInterval = 5 * 60; // 5 分钟
self.tableView.delegate = self; self.tableView.delegate = self;
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
self.tableView.backgroundColor = [UIColor clearColor]; self.tableView.backgroundColor = [UIColor clearColor];
self.tableView.estimatedRowHeight = 60; // 使0
self.tableView.estimatedRowHeight = 80;
self.tableView.estimatedSectionHeaderHeight = 0;
self.tableView.estimatedSectionFooterHeight = 0;
self.tableView.rowHeight = UITableViewAutomaticDimension; self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.showsVerticalScrollIndicator = YES; self.tableView.showsVerticalScrollIndicator = YES;
// CollectionView
if (@available(iOS 11.0, *)) {
self.tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}
[self addSubview:self.tableView]; [self addSubview:self.tableView];
// Cell // Cell
@@ -182,13 +189,22 @@ static const NSTimeInterval kTimestampInterval = 5 * 60; // 5 分钟
} }
- (void)scrollToBottom { - (void)scrollToBottom {
[self scrollToBottomAnimated:YES];
}
- (void)scrollToBottomAnimated:(BOOL)animated {
if (self.messages.count == 0) return; if (self.messages.count == 0) return;
// 使 layoutIfNeeded
[self.tableView layoutIfNeeded];
NSIndexPath *lastIndexPath = [NSIndexPath indexPathForRow:self.messages.count - 1 NSIndexPath *lastIndexPath = [NSIndexPath indexPathForRow:self.messages.count - 1
inSection:0]; inSection:0];
//
[self.tableView scrollToRowAtIndexPath:lastIndexPath [self.tableView scrollToRowAtIndexPath:lastIndexPath
atScrollPosition:UITableViewScrollPositionBottom atScrollPosition:UITableViewScrollPositionBottom
animated:YES]; animated:animated];
} }
#pragma mark - Public Helpers #pragma mark - Public Helpers
@@ -240,6 +256,10 @@ static const NSTimeInterval kTimestampInterval = 5 * 60; // 5 分钟
for (NSInteger i = oldCount; i < newCount; i++) { for (NSInteger i = oldCount; i < newCount; i++) {
[indexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]]; [indexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]];
} }
//
[self.tableView layoutIfNeeded];
[self.tableView insertRowsAtIndexPaths:indexPaths [self.tableView insertRowsAtIndexPaths:indexPaths
withRowAnimation:UITableViewRowAnimationNone]; withRowAnimation:UITableViewRowAnimationNone];
} }
@@ -247,8 +267,10 @@ static const NSTimeInterval kTimestampInterval = 5 * 60; // 5 分钟
[self updateFooterVisibility]; [self updateFooterVisibility];
if (autoScroll) { if (autoScroll) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // 使 dispatch_async
[self scrollToBottom]; dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView layoutIfNeeded]; //
[self scrollToBottomAnimated:YES];
}); });
} }
} }
@@ -274,14 +296,14 @@ static const NSTimeInterval kTimestampInterval = 5 * 60; // 5 分钟
CGFloat newContentHeight = self.tableView.contentSize.height; CGFloat newContentHeight = self.tableView.contentSize.height;
CGFloat delta = newContentHeight - oldContentHeight; CGFloat delta = newContentHeight - oldContentHeight;
CGFloat offsetY = oldOffsetY + delta; CGFloat offsetY = oldOffsetY + delta;
// 使 offset
[self.tableView setContentOffset:CGPointMake(0, offsetY) animated:NO]; [self.tableView setContentOffset:CGPointMake(0, offsetY) animated:NO];
return; return;
} }
if (scrollToBottom) { if (scrollToBottom) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // 使
[self scrollToBottom]; [self scrollToBottomAnimated:NO];
});
} }
} }
@@ -430,6 +452,31 @@ static const NSTimeInterval kTimestampInterval = 5 * 60; // 5 分钟
} }
} }
///
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView
withVelocity:(CGPoint)velocity
targetContentOffset:(inout CGPoint *)targetContentOffset {
CGFloat offsetY = scrollView.contentOffset.y;
CGFloat contentHeight = scrollView.contentSize.height;
CGFloat scrollViewHeight = scrollView.bounds.size.height;
//
if (contentHeight <= scrollViewHeight) {
scrollView.bounces = NO;
} else {
scrollView.bounces = YES;
//
if (velocity.y < 0) { //
CGFloat maxOffset = contentHeight - scrollViewHeight + scrollView.contentInset.bottom;
if (targetContentOffset->y > maxOffset) {
targetContentOffset->y = maxOffset;
}
}
}
}
#pragma mark - KBChatAssistantMessageCellDelegate #pragma mark - KBChatAssistantMessageCellDelegate
- (void)assistantMessageCell:(KBChatAssistantMessageCell *)cell - (void)assistantMessageCell:(KBChatAssistantMessageCell *)cell

View File

@@ -61,6 +61,18 @@
return self; return self;
} }
/// Cell
- (void)prepareForReuse {
[super prepareForReuse];
//
[self.chatView stopPlayingAudio];
//
self.isLoading = NO;
self.hasLoadedData = NO;
}
#pragma mark - 1 #pragma mark - 1
- (void)setupUI { - (void)setupUI {
@@ -130,6 +142,8 @@
self.nameLabel.text = persona.name; self.nameLabel.text = persona.name;
self.openingLabel.text = persona.shortDesc.length > 0 ? persona.shortDesc : persona.introText; self.openingLabel.text = persona.shortDesc.length > 0 ? persona.shortDesc : persona.introText;
//
[self.chatView stopPlayingAudio];
[self.chatView clearMessages]; [self.chatView clearMessages];
} }

View File

@@ -65,6 +65,9 @@
/// AiVM /// AiVM
@property (nonatomic, strong) AiVM *aiVM; @property (nonatomic, strong) AiVM *aiVM;
/// AI
@property (nonatomic, assign) BOOL isWaitingForAIResponse;
@end @end
@implementation KBAIHomeVC @implementation KBAIHomeVC
@@ -83,6 +86,7 @@
self.currentIndex = 0; self.currentIndex = 0;
self.preloadedIndexes = [NSMutableSet set]; self.preloadedIndexes = [NSMutableSet set];
self.aiVM = [[AiVM alloc] init]; self.aiVM = [[AiVM alloc] init];
self.isWaitingForAIResponse = NO; //
[self setupUI]; [self setupUI];
[self setupVoiceToTextManager]; [self setupVoiceToTextManager];
@@ -259,6 +263,11 @@
#pragma mark - UIScrollViewDelegate #pragma mark - UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView { - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
// AI
if (self.isWaitingForAIResponse) {
return;
}
CGFloat pageHeight = scrollView.bounds.size.height; CGFloat pageHeight = scrollView.bounds.size.height;
CGFloat offsetY = scrollView.contentOffset.y; CGFloat offsetY = scrollView.contentOffset.y;
NSInteger currentPage = offsetY / pageHeight; NSInteger currentPage = offsetY / pageHeight;
@@ -288,6 +297,16 @@
[self updateChatViewBottomInset]; [self updateChatViewBottomInset];
} }
/// AI
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
if (self.isWaitingForAIResponse) {
NSLog(@"[KBAIHomeVC] 正在等待 AI 回复,禁止滚动");
//
scrollView.scrollEnabled = NO;
scrollView.scrollEnabled = YES;
}
}
#pragma mark - 4 #pragma mark - 4
- (void)setupVoiceToTextManager { - (void)setupVoiceToTextManager {
@@ -607,6 +626,11 @@
[currentCell appendUserMessage:text]; [currentCell appendUserMessage:text];
} }
// CollectionView
self.isWaitingForAIResponse = YES;
self.collectionView.scrollEnabled = NO;
NSLog(@"[KBAIHomeVC] 开始等待 AI 回复,禁止 CollectionView 滚动");
__weak typeof(self) weakSelf = self; __weak typeof(self) weakSelf = self;
[self.aiVM requestChatMessageWithContent:text [self.aiVM requestChatMessageWithContent:text
companionId:companionId companionId:companionId
@@ -617,10 +641,10 @@
} }
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
// if (error) { // CollectionView
// NSLog(@"[KBAIHomeVC] 请求聊天失败:%@", error.localizedDescription); strongSelf.isWaitingForAIResponse = NO;
// return; strongSelf.collectionView.scrollEnabled = YES;
// } NSLog(@"[KBAIHomeVC] AI 回复完成,恢复 CollectionView 滚动");
if (response.code == 50030) { if (response.code == 50030) {
NSString *message = response.message ?: @""; NSString *message = response.message ?: @"";