// // EPMomentListView.m // YuMi // // Created by AI on 2025-10-10. // #import #import "EPMomentListView.h" #import "EPMomentCell.h" #import @interface EPMomentListView () @property (nonatomic, strong) UITableView *tableView; @property (nonatomic, strong) UIRefreshControl *refreshControl; @property (nonatomic, strong) NSMutableArray *mutableRawList; @property (nonatomic, strong) EPMomentAPIHelper *api; @property (nonatomic, assign) BOOL isLoading; @property (nonatomic, copy) NSString *nextID; @property (nonatomic, assign) BOOL isLocalMode; @property (nonatomic, copy) void (^refreshCallback)(void); @end @implementation EPMomentListView - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { self.backgroundColor = [UIColor clearColor]; _api = [[EPMomentAPIHelper alloc] init]; _mutableRawList = [NSMutableArray array]; _sourceType = EPMomentListSourceTypeRecommend; [self addSubview:self.tableView]; [self.tableView mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self); }]; } return self; } - (NSArray *)rawList { return [self.mutableRawList copy]; } - (void)reloadFirstPage { if (self.isLocalMode) { // 本地模式:调用外部刷新回调 if (self.refreshCallback) { self.refreshCallback(); } [self.refreshControl endRefreshing]; return; } // 网络模式:重新请求第一页 self.nextID = @""; [self.mutableRawList removeAllObjects]; [self.tableView reloadData]; [self.tableView.mj_footer resetNoMoreData]; [self requestNextPage]; } - (void)loadWithDynamicInfo:(NSArray *)dynamicInfo refreshCallback:(void (^)(void))refreshCallback { self.isLocalMode = YES; self.refreshCallback = refreshCallback; [self.mutableRawList removeAllObjects]; if (dynamicInfo.count > 0) { [self.mutableRawList addObjectsFromArray:dynamicInfo]; } // 隐藏加载更多 footer self.tableView.mj_footer.hidden = YES; [self.tableView reloadData]; [self.refreshControl endRefreshing]; } - (void)requestNextPage { if (self.isLoading) return; self.isLoading = YES; @kWeakify(self); [self.api fetchLatestMomentsWithNextID:self.nextID completion:^(NSArray * _Nullable list, NSString * _Nonnull nextMomentID) { @kStrongify(self); [self endLoading]; if (list.count > 0) { self.nextID = nextMomentID; [self.mutableRawList addObjectsFromArray:list]; [self.tableView reloadData]; if (nextMomentID.length > 0) { [self.tableView.mj_footer endRefreshing]; } else { [self.tableView.mj_footer endRefreshingWithNoMoreData]; } } else { // TODO: 后续补充空数据页面 if (self.nextID.length == 0) { [self.tableView.mj_footer endRefreshingWithNoMoreData]; } else { [self.tableView.mj_footer endRefreshing]; } } } failure:^(NSInteger code, NSString * _Nullable msg) { @kStrongify(self); [self endLoading]; // TODO: 完全没有数据情况下,后续补充数据异常页面 [self.tableView.mj_footer endRefreshing]; }]; } - (void)endLoading { self.isLoading = NO; [self.refreshControl endRefreshing]; } #pragma mark - UITableView - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.mutableRawList.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { EPMomentCell *cell = [tableView dequeueReusableCellWithIdentifier:@"NewMomentCell" forIndexPath:indexPath]; if (indexPath.row < self.mutableRawList.count) { MomentsInfoModel *model = [self.mutableRawList xpSafeObjectAtIndex:indexPath.row]; [cell configureWithModel:model]; } return cell; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return UITableViewAutomaticDimension; } - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath { return 200; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:YES]; if (self.onSelectMoment) self.onSelectMoment(indexPath.row); } - (void)scrollViewDidScroll:(UIScrollView *)scrollView { // 本地模式下不触发加载更多 if (self.isLocalMode) return; CGFloat offsetY = scrollView.contentOffset.y; CGFloat contentHeight = scrollView.contentSize.height; CGFloat screenHeight = scrollView.frame.size.height; if (offsetY > contentHeight - screenHeight - 100 && !self.isLoading) { [self requestNextPage]; } } #pragma mark - Lazy - (UITableView *)tableView { if (!_tableView) { _tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain]; _tableView.delegate = self; _tableView.dataSource = self; _tableView.separatorStyle = UITableViewCellSeparatorStyleNone; _tableView.backgroundColor = [UIColor clearColor]; _tableView.estimatedRowHeight = 200; _tableView.rowHeight = UITableViewAutomaticDimension; _tableView.showsVerticalScrollIndicator = NO; // 底部留出更高空间,避免被悬浮 TabBar 遮挡 _tableView.contentInset = UIEdgeInsetsMake(10, 0, 120, 0); _tableView.scrollIndicatorInsets = UIEdgeInsetsMake(10, 0, 120, 0); [_tableView registerClass:[EPMomentCell class] forCellReuseIdentifier:@"NewMomentCell"]; _tableView.refreshControl = self.refreshControl; // MJRefresh Footer - 加载更多 __weak typeof(self) weakSelf = self; _tableView.mj_footer = [MJRefreshAutoNormalFooter footerWithRefreshingBlock:^{ __strong typeof(weakSelf) self = weakSelf; if (!self.isLoading && self.nextID.length > 0) { [self requestNextPage]; } else if (self.nextID.length == 0) { [self.tableView.mj_footer endRefreshingWithNoMoreData]; } else { [self.tableView.mj_footer endRefreshing]; } }]; } return _tableView; } - (UIRefreshControl *)refreshControl { if (!_refreshControl) { _refreshControl = [[UIRefreshControl alloc] init]; [_refreshControl addTarget:self action:@selector(reloadFirstPage) forControlEvents:UIControlEventValueChanged]; } return _refreshControl; } @end