在 cellForRowAtIndexPath 中為每個 Cell 動態創建 UIButton,點擊按鈕切換圖片(如關注/取消關注),但滾動列表後按鈕狀態恢復初始狀態。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell4";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [self tableviewCellWithReuseIdentifierFollowing:CellIdentifier];
}
// 錯誤:每次獲取 cell 都重新創建按鈕並設置默認圖片
followingButton = [UIButton buttonWithType:UIButtonTypeCustom];
[followingButton setImage:[UIImage imageNamed:@"following12.png"] forState:UIControlStateNormal];
// ... 添加 target、frame、tag ...
[cell.contentView addSubview:followingButton];
return cell;
}
核心錯誤:按鈕創建與默認圖片設置在 if (cell == nil) 之外,導致 Cell 復用時重複添加子視圖、重置圖片。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell4";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
// 1. 僅創建一次按鈕
UIButton *followingButton = [UIButton buttonWithType:UIButtonTypeCustom];
followingButton.tag = 100; // 固定 tag 方便取回
[followingButton addTarget:self action:@selector(followingButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
[followingButton setImage:[UIImage imageNamed:@"following12.png"] forState:UIControlStateNormal];
followingButton.frame = CGRectMake(220, 20, 100, 40);
[cell.contentView addSubview:followingButton];
}
// 2. 獲取已存在的按鈕
UIButton *followingButton = (UIButton *)[cell.contentView viewWithTag:100];
// 3. 根據數據模型設置當前狀態(關鍵:同步模型狀態到 UI)
MyDataModel *model = self.dataArray[indexPath.row];
[followingButton setSelected:model.isFollowed]; // 模型驅動 UI
[followingButton setImage:model.isFollowed ? [UIImage imageNamed:@"following_off12.png"] : [UIImage imageNamed:@"following12.png"]
forState:UIControlStateNormal];
// 4. 存儲 indexPath 供點擊事件使用
followingButton.tag = indexPath.row; // 復用 tag 傳遞行號
return cell;
}
- (void)followingButtonPressed:(UIButton *)sender {
NSInteger row = sender.tag;
MyDataModel *model = self.dataArray[row];
// 1. 翻轉模型狀態
model.isFollowed = !model.isFollowed;
// 2. 可選:發送網絡請求,失敗時回滾 model.isFollowed
// 3. 刷新對應行(最佳體驗)
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:0];
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
// 或僅更新按鈕(若確定 cell 可見)
// UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
// UIButton *btn = (UIButton *)[cell.contentView viewWithTag:100];
// [btn setSelected:model.isFollowed];
}
if (cell == nil) 內。reloadRowsAtIndexPaths 或直接取 cell 更新)。// FollowCell.h
@property (nonatomic, weak) IBOutlet UIButton *followButton;
- (void)configureWithModel:(MyDataModel *)model delegate:(id)delegate;
// FollowCell.m
- (void)configureWithModel:(MyDataModel *)model delegate:(id)delegate {
self.followButton.selected = model.isFollowed;
[self.followButton setImage:model.isFollowed ? offImage : onImage forState:UIControlStateNormal];
// 使用 block 或 delegate 回調點擊,避免 tag 傳遞行號
self.followButtonTapHandler = ^{
model.isFollowed = !model.isFollowed;
delegate?.didTapFollowButton(model);
};
}
使用自定義 Cell + XIB/Storyboard + Block 回調,代碼更清晰、類型安全、易維護。