一、概述
UITbableView作為列表展示信息,除了展示的功能,有時還會用到刪除,比如購物車
、收藏列表
等。
- 單行刪除:可以直接使用系統自帶的刪除功能,當橫向輕掃cell時,右側出現紅色的刪除按鈕,點擊刪除當前cell。或者讓表格進入編輯狀態后,點擊左側的紅色按鈕,右側出現刪除按鈕,即可刪除當前cell。可參照:iOS UITableView刪除功能
- 多選刪除:點擊編輯按鈕,讓表格進入編輯狀態后,每行的左側出現一個小圓圈,當點擊行的時候,可以選中該行或者取消選中該行,當點擊刪除按鈕的時候才會把選中的行全部刪除掉。
二、效果圖
系統樣式效果圖.gif
三、技術分析
- 讓tableView進入編輯狀態,即
tableView.editing = YES
。
// 取消
[self.tableView setEditing:YES animated:NO];
- 返回編輯模式,即實現
UITableViewDelegate
中的- tableview:editingStyleForRowAtIndexPath:
方法,在里面返回多選模式即UITableViewCellEditingStyleDelete | UITableViewCellEditingStyleInsert
。如果不實現,默認返回的就是刪除模式即UITableViewCellEditingStyleDelete
。
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (tableView.isEditing) {
// 多選
return UITableViewCellEditingStyleDelete | UITableViewCellEditingStyleInsert;
}else{
// 刪除
return UITableViewCellEditingStyleDelete;
}
}
- 返回編輯模式,即實現
UITableViewDelegate
中的- tableview:editingStyleForRowAtIndexPath:
方法,在里面返回多選模式即UITableViewCellEditingStyleDelete | UITableViewCellEditingStyleInsert
。如果不實現,默認返回的就是刪除模式即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:@"仙劍奇俠傳 第%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];
}
}
- 點擊刪除按鈕,刪除數據源的數據和tableView中所對應的cell。
// delete收藏視頻
- (void)_deleteSelectIndexPaths:(NSArray *)indexPaths
{
// 刪除數據源
[self.dataSource removeObjectsInArray:self.selectedDatas];
[self.selectedDatas removeAllObjects];
// 刪除選中項
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
// 驗證數據源
[self _indexPathsForSelectedRowsCountDidChange:self.tableView.indexPathsForSelectedRows];
// 驗證沒有數據的情況 沒有數據 右側按鈕 不能點擊 細節處理
if (self.dataSource.count == 0)
{
//沒有收藏數據
if(self.rightBarButtonItem.selected)
{
// 編輯狀態 -- 取消編輯狀態
[self _rightBarButtonItemDidClicked:self.rightBarButtonItem];
}
self.rightBarButtonItem.enabled = NO;
}
}
四、細節處理
- 側滑狀態下點擊
編輯
按鈕的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];
}
}
五、拓展
-
如果客戶想用系統自帶的多選功能,但是要改變選中按鈕的樣式。例如下圖所示:
自定義樣式效果圖.gif -
由于該選中圖片在界面上已經顯示出來了,那肯定是存在的。可以調用 [cell subviews]方法尋找。猜想可能是UIControl的子類。打印Cell的子控件如下圖所示: 由下圖不難看出,此時選中的cell中有四個子視圖類名分別為:
UIView
,UITableViewCellContentView
,_UITableViewSeparatorView
,UITableViewCellEditControl
。UITableViewCellEditControl
肯定是我們想要的,正好里面還有一個imageView
屬性。但是查詢UITableViewCell
的關于UITableViewCellEditControl
的API,并未發現關于其的解釋,則利用KVC(key-value-coding
)鍵值編碼,對OC這門動態語言量身定制,利用runtime運行時原理動態為對象設置屬性。
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"];
}
}
}
}
}
- 由于編輯狀態下點擊
Cell
,就得調用- (void)_changeCellSelectedImage
這個方法修改選中按鈕的樣式。以及長按Cell
也得修改樣式,根據MVC
設計模式的原則,自定義Cell
,監聽Cell
的選中狀態
和高亮狀態
,從而將業務邏輯屏蔽起來。
/** 選中cell的時候調用 */
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// 非編輯狀態下 直接退出
if (!self.isEditing) return;
// 非修改系統選中圖標樣式
if (!self.isModifySelectionStyle) return;
// 修改系統選擇按鈕的樣式
if (selected) {
// 改變
[self _changeCellSelectedImage];
}
}
/** 長按cell高亮狀態下 */
- (void) setHighlighted:(BOOL)highlighted animated:(BOOL)animated
{
[super setHighlighted:highlighted animated:animated];
// 非編輯狀態下 直接退出
if (!self.isEditing) return;
// 非修改系統選中圖標樣式
if (!self.isModifySelectionStyle) return;
if (highlighted) {
// 改變
[self _changeCellSelectedImage];
}
}
- 編輯的情況下,Cell的
選中狀態下
和高亮狀態
都會調用- (void)_changeCellSelectedImage
這個方法,但該方法內部是在遍歷Cell
的子控件,若選中過于頻繁,則會占用一點內存(注:Cell
的子控件只有四個,其實影響不大)。則需要利用緩存機制了。Demo中未做緩存處理。
五、期待
- 文章若對您有點幫助,請給個喜歡??;若沒啥幫助,請給點建議。
- 針對文章所述,您閱讀有什么疑問;或使用Demo中有什么bug。請在文章底部評論,我會盡快解決問題。
- GitHub地址:https://github.com/CoderMikeHe