一、概述
UITbableView作為列表展示信息,除了展示的功能,有時還會用到刪除,比如購物車、收藏列表等。
- 單行刪除:可以直接使用系統(tǒng)自帶的刪除功能,當橫向輕掃cell時,右側出現(xiàn)紅色的刪除按鈕,點擊刪除當前cell。或者讓表格進入編輯狀態(tài)后,點擊左側的紅色按鈕,右側出現(xiàn)刪除按鈕,即可刪除當前cell??蓞⒄眨?a href="http://www.itdecent.cn/p/4c53901062eb" target="_blank">iOS UITableView刪除功能
- 多選刪除:點擊編輯按鈕,讓表格進入編輯狀態(tài)后,每行的左側出現(xiàn)一個小圓圈,當點擊行的時候,可以選中該行或者取消選中該行,當點擊刪除按鈕的時候才會把選中的行全部刪除掉。
二、效果圖

系統(tǒng)樣式效果圖.gif
三、技術分析
- 讓tableView進入編輯狀態(tài),即
tableView.editing = YES。
// 取消
[self.tableView setEditing:YES animated:NO];
- 返回編輯模式,即實現(xiàn)
UITableViewDelegate中的- tableview:editingStyleForRowAtIndexPath:方法,在里面返回多選模式即UITableViewCellEditingStyleDelete | UITableViewCellEditingStyleInsert。如果不實現(xiàn),默認返回的就是刪除模式即UITableViewCellEditingStyleDelete。
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (tableView.isEditing) {
// 多選
return UITableViewCellEditingStyleDelete | UITableViewCellEditingStyleInsert;
}else{
// 刪除
return UITableViewCellEditingStyleDelete;
}
}
- 返回編輯模式,即實現(xiàn)
UITableViewDelegate中的- tableview:editingStyleForRowAtIndexPath:方法,在里面返回多選模式即UITableViewCellEditingStyleDelete | UITableViewCellEditingStyleInsert。如果不實現(xiàn),默認返回的就是刪除模式即UITableViewCellEditingStyleDelete。
// 選中
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (tableView.isEditing) {
NSIndexPath *indexPathM = self.dataSource[indexPath.row];
if (![self.selectedDatas containsObject:indexPathM]) {
[self.selectedDatas addObject:indexPathM];
}
[self _indexPathsForSelectedRowsCountDidChange:tableView.indexPathsForSelectedRows];
return;
}
MHOperationController *operation = [[MHOperationController alloc] init];
NSIndexPath *indexP = self.dataSource[indexPath.row];
operation.title = [NSString stringWithFormat:@"仙劍奇?zhèn)b傳 第%zd集",indexP.row];
[self.navigationController pushViewController:operation animated:YES];
}
// 取消選中
- (void) tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (tableView.isEditing)
{
NSIndexPath *indexPathM = self.dataSource[indexPath.row];
if ([self.selectedDatas containsObject:indexPathM]) {
[self.selectedDatas removeObject:indexPathM];
}
[self _indexPathsForSelectedRowsCountDidChange:tableView.indexPathsForSelectedRows];
}
}
- 點擊刪除按鈕,刪除數(shù)據(jù)源的數(shù)據(jù)和tableView中所對應的cell。
// delete收藏視頻
- (void)_deleteSelectIndexPaths:(NSArray *)indexPaths
{
// 刪除數(shù)據(jù)源
[self.dataSource removeObjectsInArray:self.selectedDatas];
[self.selectedDatas removeAllObjects];
// 刪除選中項
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
// 驗證數(shù)據(jù)源
[self _indexPathsForSelectedRowsCountDidChange:self.tableView.indexPathsForSelectedRows];
// 驗證沒有數(shù)據(jù)的情況 沒有數(shù)據(jù) 右側按鈕 不能點擊 細節(jié)處理
if (self.dataSource.count == 0)
{
//沒有收藏數(shù)據(jù)
if(self.rightBarButtonItem.selected)
{
// 編輯狀態(tài) -- 取消編輯狀態(tài)
[self _rightBarButtonItemDidClicked:self.rightBarButtonItem];
}
self.rightBarButtonItem.enabled = NO;
}
}
四、細節(jié)處理
- 側滑狀態(tài)下點擊
編輯按鈕的bug。
// 編輯按鈕的點擊事件
- (void)_rightBarButtonItemDidClicked:(UIButton *)sender
{
sender.selected = !sender.isSelected;
if (sender.isSelected) {
// 這個是fix掉:當你左滑刪除的時候,再點擊右上角編輯按鈕, cell上的刪除按鈕不會消失掉的bug。且必須放在 設置tableView.editing = YES;的前面。
[self.tableView reloadData];
// 取消
[self.tableView setEditing:YES animated:NO];
// 全選
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:self.leftBarButtonItem];
self.leftBarButtonItem.selected = NO;
// show
[self _showDeleteButton];
}else{
// 清空選中欄
[self.selectedDatas removeAllObjects];
// 編輯
[self.tableView setEditing:NO animated:NO];
// 返回
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:self.backBarButtonItem];
// hide
[self _hideDeleteButton];
}
}
五、拓展
-
如果客戶想用系統(tǒng)自帶的多選功能,但是要改變選中按鈕的樣式。例如下圖所示:
自定義樣式效果圖.gif -
由于該選中圖片在界面上已經(jīng)顯示出來了,那肯定是存在的??梢哉{用 [cell subviews]方法尋找。猜想可能是UIControl的子類。打印Cell的子控件如下圖所示: 由下圖不難看出,此時選中的cell中有四個子視圖類名分別為:
UIView,UITableViewCellContentView,_UITableViewSeparatorView,UITableViewCellEditControl。UITableViewCellEditControl肯定是我們想要的,正好里面還有一個imageView屬性。但是查詢UITableViewCell的關于UITableViewCellEditControl的API,并未發(fā)現(xiàn)關于其的解釋,則利用KVC(key-value-coding)鍵值編碼,對OC這門動態(tài)語言量身定制,利用runtime運行時原理動態(tài)為對象設置屬性。
cell子控件@2x.png 修改選中按鈕的樣式
/** 修改選中按鈕的樣式 */
- (void)_changeCellSelectedImage
{
// 利用KVC 設置color
for (UIView *view in self.subviews) {
if ([view isKindOfClass:[UIControl class]])
{
for (UIView *subview in view.subviews) {
if ([subview isKindOfClass:[UIImageView class]])
{
// MHGlobalOrangeTextColor :淺橙色
[subview setValue:MHGlobalOrangeTextColor forKey:@"tintColor"];
}
}
}
}
}
- 由于編輯狀態(tài)下點擊
Cell,就得調用- (void)_changeCellSelectedImage這個方法修改選中按鈕的樣式。以及長按Cell也得修改樣式,根據(jù)MVC設計模式的原則,自定義Cell,監(jiān)聽Cell的選中狀態(tài)和高亮狀態(tài),從而將業(yè)務邏輯屏蔽起來。
/** 選中cell的時候調用 */
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// 非編輯狀態(tài)下 直接退出
if (!self.isEditing) return;
// 非修改系統(tǒng)選中圖標樣式
if (!self.isModifySelectionStyle) return;
// 修改系統(tǒng)選擇按鈕的樣式
if (selected) {
// 改變
[self _changeCellSelectedImage];
}
}
/** 長按cell高亮狀態(tài)下 */
- (void) setHighlighted:(BOOL)highlighted animated:(BOOL)animated
{
[super setHighlighted:highlighted animated:animated];
// 非編輯狀態(tài)下 直接退出
if (!self.isEditing) return;
// 非修改系統(tǒng)選中圖標樣式
if (!self.isModifySelectionStyle) return;
if (highlighted) {
// 改變
[self _changeCellSelectedImage];
}
}
- 編輯的情況下,Cell的
選中狀態(tài)下和高亮狀態(tài)都會調用- (void)_changeCellSelectedImage這個方法,但該方法內部是在遍歷Cell的子控件,若選中過于頻繁,則會占用一點內存(注:Cell的子控件只有四個,其實影響不大)。則需要利用緩存機制了。Demo中未做緩存處理。
五、期待
- 文章若對您有點幫助,請給個喜歡??;若沒啥幫助,請給點建議。
- 針對文章所述,您閱讀有什么疑問;或使用Demo中有什么bug。請在文章底部評論,我會盡快解決問題。
- GitHub地址:https://github.com/CoderMikeHe

