在 `UICollectionView` 中實現「點擊 Cell 內的 + 按鈕,更新該 Cell 的計數 Label」是常見交互需求。核心難點在於按鈕點擊事件中定位所屬 IndexPath並精準更新對應 Cell。
// Cell 配置階段
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath {
MyCell *cell = [cv dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath];
cell.plusButton.tag = indexPath.item; // 關鍵:存儲 index
[cell.plusButton addTarget:self action:@selector(plusBtnTapped:) forControlEvents:UIControlEventTouchUpInside];
return cell;
}
// 按鈕點擊處理
- (void)plusBtnTapped:(UIButton *)sender {
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:sender.tag inSection:0];
// 方式 A: 直接獲取 Cell 更新 (僅可見 Cell 有效)
MyCell *cell = (MyCell *)[self.collectionView cellForItemAtIndexPath:indexPath];
if (cell) {
cell.updateCountLabel(with: newCount);
}
// 方式 B: 更新數據源 + reloadItem (通用、安全)
self.dataArray[indexPath.item] = @(newCount);
[self.collectionView reloadItemsAtIndexPaths:@[indexPath]];
}
// MyCell.h
@property (nonatomic, copy) void(^plusButtonTappedBlock)(NSInteger index);
// MyCell.m
- (IBAction)plusButtonTapped:(UIButton *)sender {
if (self.plusButtonTappedBlock) {
self.plusButtonTappedBlock(self.index); // 需在 cellForItemAtIndexPath 中設置 self.index
}
}
// Controller
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath {
MyCell *cell = [cv dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath];
cell.index = indexPath.item;
cell.plusButtonTappedBlock = ^(NSInteger index) {
// 更新數據源
self.dataArray[index] = @(newCount);
// 精準刷新
[cv reloadItemsAtIndexPaths:@[[NSIndexPath indexPathForItem:index inSection:0]]];
};
return cell;
}
// Swift 版本
func collectionView(_ cv: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = cv.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! MyCell
cell.configure(with: data[indexPath.item]) {
// 閉包捕獲 indexPath
self.data[indexPath.item].count += 1
cv.reloadItems(at: [indexPath])
}
return cell
}
// MyCell.swift
var onPlusTapped: (() -> Void)?
@IBAction func plusTapped(_ sender: UIButton) {
onPlusTapped?()
}
// performBatchUpdates 批量動畫更新
collectionView.performBatchUpdates({
// 多個 indexPath 同時更新
self.dataArray[index1] = newValue1
self.dataArray[index2] = newValue2
self.collectionView.reloadItems(at: [index1, index2])
}, completion: nil)
核心口訣:按鈕傳 IndexPath → 更新 Model → 精準 Reload,符合 MVC/MVVM 數據流向,穩健高效。