新增接口,界面
This commit is contained in:
244
keyBoard/Class/AiTalk/VC/KBAIHomeVC.m
Normal file
244
keyBoard/Class/AiTalk/VC/KBAIHomeVC.m
Normal file
@@ -0,0 +1,244 @@
|
||||
//
|
||||
// KBAIHomeVC.m
|
||||
// keyBoard
|
||||
//
|
||||
// Created by Mac on 2026/1/26.
|
||||
//
|
||||
|
||||
#import "KBAIHomeVC.h"
|
||||
#import "KBPersonaChatCell.h"
|
||||
#import "KBPersonaModel.h"
|
||||
#import "AiVM.h"
|
||||
#import <Masonry/Masonry.h>
|
||||
|
||||
@interface KBAIHomeVC () <UICollectionViewDelegate, UICollectionViewDataSource>
|
||||
|
||||
/// 人设列表容器
|
||||
@property (nonatomic, strong) UICollectionView *collectionView;
|
||||
|
||||
/// 人设数据
|
||||
@property (nonatomic, strong) NSMutableArray<KBPersonaModel *> *personas;
|
||||
|
||||
/// 当前页码
|
||||
@property (nonatomic, assign) NSInteger currentPage;
|
||||
|
||||
/// 是否还有更多数据
|
||||
@property (nonatomic, assign) BOOL hasMore;
|
||||
|
||||
/// 是否正在加载
|
||||
@property (nonatomic, assign) BOOL isLoading;
|
||||
|
||||
/// 当前显示的索引
|
||||
@property (nonatomic, assign) NSInteger currentIndex;
|
||||
|
||||
/// 已预加载的索引集合
|
||||
@property (nonatomic, strong) NSMutableSet<NSNumber *> *preloadedIndexes;
|
||||
|
||||
/// AiVM 实例
|
||||
@property (nonatomic, strong) AiVM *aiVM;
|
||||
|
||||
@end
|
||||
|
||||
@implementation KBAIHomeVC
|
||||
|
||||
#pragma mark - Lifecycle
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
self.view.backgroundColor = [UIColor whiteColor];
|
||||
self.kb_navView.hidden = true;
|
||||
// 初始化数据
|
||||
self.personas = [NSMutableArray array];
|
||||
self.currentPage = 1;
|
||||
self.hasMore = YES;
|
||||
self.isLoading = NO;
|
||||
self.currentIndex = 0;
|
||||
self.preloadedIndexes = [NSMutableSet set];
|
||||
self.aiVM = [[AiVM alloc] init];
|
||||
|
||||
[self setupUI];
|
||||
[self loadPersonas];
|
||||
}
|
||||
|
||||
#pragma mark - 1:控件初始化
|
||||
|
||||
- (void)setupUI {
|
||||
[self.view addSubview:self.collectionView];
|
||||
[self.collectionView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.equalTo(self.view);
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - 2:数据加载
|
||||
|
||||
- (void)loadPersonas {
|
||||
if (self.isLoading) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.isLoading = YES;
|
||||
|
||||
__weak typeof(self) weakSelf = self;
|
||||
[self.aiVM fetchPersonasWithPageNum:self.currentPage
|
||||
pageSize:10
|
||||
completion:^(KBPersonaPageModel * _Nullable pageModel, NSError * _Nullable error) {
|
||||
weakSelf.isLoading = NO;
|
||||
|
||||
if (error) {
|
||||
NSLog(@"加载人设列表失败:%@", error.localizedDescription);
|
||||
// TODO: 显示错误提示
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pageModel || !pageModel.records) {
|
||||
NSLog(@"人设列表数据为空");
|
||||
return;
|
||||
}
|
||||
|
||||
// 追加数据
|
||||
[weakSelf.personas addObjectsFromArray:pageModel.records];
|
||||
weakSelf.hasMore = pageModel.hasMore;
|
||||
|
||||
// 刷新 UI
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[weakSelf.collectionView reloadData];
|
||||
|
||||
// 首次加载,预加载前 3 个
|
||||
if (weakSelf.currentPage == 1) {
|
||||
[weakSelf preloadDataForIndexes:@[@0, @1, @2]];
|
||||
}
|
||||
});
|
||||
|
||||
NSLog(@"加载成功:当前 %ld 条,总共 %ld 条,还有更多:%@",
|
||||
weakSelf.personas.count,
|
||||
pageModel.total,
|
||||
pageModel.hasMore ? @"是" : @"否");
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)loadMorePersonas {
|
||||
if (!self.hasMore || self.isLoading) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.currentPage++;
|
||||
[self loadPersonas];
|
||||
}
|
||||
|
||||
#pragma mark - 3:预加载逻辑
|
||||
|
||||
- (void)preloadAdjacentCellsForIndex:(NSInteger)index {
|
||||
if (index < 0 || index >= self.personas.count) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSMutableArray *indexesToPreload = [NSMutableArray array];
|
||||
|
||||
// 上一个
|
||||
if (index > 0) {
|
||||
[indexesToPreload addObject:@(index - 1)];
|
||||
}
|
||||
|
||||
// 当前
|
||||
[indexesToPreload addObject:@(index)];
|
||||
|
||||
// 下一个
|
||||
if (index < self.personas.count - 1) {
|
||||
[indexesToPreload addObject:@(index + 1)];
|
||||
}
|
||||
|
||||
[self preloadDataForIndexes:indexesToPreload];
|
||||
}
|
||||
|
||||
- (void)preloadDataForIndexes:(NSArray<NSNumber *> *)indexes {
|
||||
for (NSNumber *indexNum in indexes) {
|
||||
if ([self.preloadedIndexes containsObject:indexNum]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
[self.preloadedIndexes addObject:indexNum];
|
||||
|
||||
NSInteger index = [indexNum integerValue];
|
||||
if (index >= self.personas.count) {
|
||||
continue;
|
||||
}
|
||||
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:index inSection:0];
|
||||
KBPersonaChatCell *cell = (KBPersonaChatCell *)[self.collectionView cellForItemAtIndexPath:indexPath];
|
||||
|
||||
if (cell) {
|
||||
[cell preloadDataIfNeeded];
|
||||
}
|
||||
|
||||
NSLog(@"预加载第 %ld 个人设", (long)index);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - UICollectionViewDataSource
|
||||
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||
return self.personas.count;
|
||||
}
|
||||
|
||||
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
KBPersonaChatCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"KBPersonaChatCell" forIndexPath:indexPath];
|
||||
cell.persona = self.personas[indexPath.item];
|
||||
return cell;
|
||||
}
|
||||
|
||||
#pragma mark - UIScrollViewDelegate
|
||||
|
||||
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
|
||||
CGFloat pageHeight = scrollView.bounds.size.height;
|
||||
CGFloat offsetY = scrollView.contentOffset.y;
|
||||
NSInteger currentPage = offsetY / pageHeight;
|
||||
|
||||
// 滑动超过 30% 就预加载
|
||||
if (fmod(offsetY, pageHeight) > pageHeight * 0.3) {
|
||||
[self preloadAdjacentCellsForIndex:currentPage + 1];
|
||||
} else {
|
||||
[self preloadAdjacentCellsForIndex:currentPage];
|
||||
}
|
||||
|
||||
// 接近底部时加载更多
|
||||
if (offsetY + scrollView.bounds.size.height >= scrollView.contentSize.height - pageHeight) {
|
||||
[self loadMorePersonas];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
|
||||
CGFloat pageHeight = scrollView.bounds.size.height;
|
||||
NSInteger currentPage = scrollView.contentOffset.y / pageHeight;
|
||||
self.currentIndex = currentPage;
|
||||
|
||||
if (currentPage < self.personas.count) {
|
||||
NSLog(@"当前在第 %ld 个人设:%@", (long)currentPage, self.personas[currentPage].name);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Lazy Load
|
||||
|
||||
- (UICollectionView *)collectionView {
|
||||
if (!_collectionView) {
|
||||
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
||||
layout.scrollDirection = UICollectionViewScrollDirectionVertical;
|
||||
layout.minimumLineSpacing = 0;
|
||||
layout.minimumInteritemSpacing = 0;
|
||||
layout.itemSize = [UIScreen mainScreen].bounds.size;
|
||||
|
||||
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
|
||||
_collectionView.pagingEnabled = YES;
|
||||
_collectionView.showsVerticalScrollIndicator = NO;
|
||||
_collectionView.backgroundColor = [UIColor whiteColor];
|
||||
_collectionView.delegate = self;
|
||||
_collectionView.dataSource = self;
|
||||
[_collectionView registerClass:[KBPersonaChatCell class] forCellWithReuseIdentifier:@"KBPersonaChatCell"];
|
||||
|
||||
if (@available(iOS 11.0, *)) {
|
||||
_collectionView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
|
||||
}
|
||||
}
|
||||
return _collectionView;
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user