UITableView 编辑总结
一、总述
在iOS开发中,UITableView的使用率可以说是非常高的,所以它在iOS开发中的地位是无法替代的。最近项目涉及到UITableView的编辑问题,这个问题其实非常广泛,我希望从我的角度尽可能地把这个问题思虑全面,讲述清楚。
UITableView的编辑,我主要从这些方面来讲述:cell的插入,删除,选择,移动排序以及UITableView的编辑模式等。
二、UITableView cell的插入
UITableView cell的插入首先要保证UITableView的数据源插入了数据,否则会发生奔溃。正确地插入了数据之后,可以通过一下几种方式达到插入Cell的效果:
1.刷新UITableView,既调用UITableView的-reloadData:方法或者-reloadSections: withRowAnimation:方法,其实还有其他的一些刷新UITableView的方式。但是我要说的是使用这种方式的话性能方面不是很好,因为刷新UITableView会调用很多次代理方法。
2.直接插入Cell,既调用UITableView的insertRowsAtIndexPaths:withRowAnimation:方法或者insertSections: withRowAnimation:方法来插入。这种方式相对性能较高。
需要注意的问题:插入了Cell最好还是调用一下UITableView的-scrollToRowAtIndexPath:atScrollPosition:UITableViewScrollPositionNoneanimated:这个方法,把UITableView滚动到对应的位置。
代码展示:
NSInteger row = self.dataArr.count - 1;
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:0];
[self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
//UITableView 滚动到添加的行
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:self.dataArr.count - 1 inSection:0] atScrollPosition:UITableViewScrollPositionNone animated:YES];
二、UITableView cell的删除
UITableView 的cell删除的效果如下:
![Uploading Simulator Screen Shot 2016年10月14日 下午5.55.04_184090.png . . .]](https://img.haomeiwen.com/i3238517/72ec984109d01951.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
Simulator Screen Shot 2016年10月14日 下午5.55.05.png
UITableView 的cell删除的步骤如下:
1.在UITableView的- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath这个代理方法中返回YES,来确定UITableView能够被编辑。
2.在UITableView的- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath这个代理方法中根据编辑的类型移除掉相应的数据,然后调用- (void)deleteRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation或者- (void)deleteSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation这个方法来删除Cell。
提示:可以在- (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath这个代理方法中设置删除按钮的文字,否则默认为delete。
代码展示:
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
- (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath
{
return @"删除";
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
[self.dataArr removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
}
else if (editingStyle == UITableViewCellEditingStyleInsert)
{
}
else
{
}
}
UITableView的编辑模式
设置UITableView的editing属性为YES可以进入编辑模式,UITableView的编辑模式有几种状态,在UITableView的- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath这个代理方法中设置,可以返回一下几种状态:
- UITableViewCellEditingStyleNone:cell往右缩进,但是左边不出现任何控件
- UITableViewCellEditingStyleDelete:cell往右缩进,但是左边出现红色减号控件
- UITableViewCellEditingStyleInsert:cell往右缩进,但是左边出现蓝色加号控件
-
UITableViewCellEditingStyleDelete|UITableViewCellEditingStyleInsert:cell往右缩进,但是左边出现选择控件
Simulator Screen Shot 2016年10月16日 下午3.37.04.png
在UITableView的- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath这个代理方法中对编辑模式时的操作(处理选择操作)进行处理,代码如下:
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
switch (indexPath.row%4) {
case 0:
return UITableViewCellEditingStyleNone;
break;
case 1:
return UITableViewCellEditingStyleDelete;
break;
case 2:
return UITableViewCellEditingStyleInsert;
break;
default:
return UITableViewCellEditingStyleDelete|UITableViewCellEditingStyleInsert;
break;
}
}
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleNone) {
}
else if (editingStyle == UITableViewCellEditingStyleDelete)
{
}
else if (editingStyle == UITableViewCellEditingStyleInsert)
{
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"添加计划" message:@"请输入明日计划" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];
[alertController addAction:cancelAction];
[self presentViewController:alertController animated:YES completion:nil];
}
else
{
}
}
UITableView cell的选择
Simulator Screen Shot 2016年10月16日 下午5.52.58.png Simulator Screen Shot 2016年10月16日 下午5.53.00.pngUITableView cell的选择,我们只需要如下几步操作即可:
1.进入编辑模式(前面已经讲过)
self.tableView.editing = YES;
2.在UITableView的- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath这个代理方法中设置编辑模式为选择的类型
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
/*
UITableView 编辑状态的样式有如下三种:
UITableViewCellEditingStyleNone:cell往右缩进,但是左边不出现任何控件
UITableViewCellEditingStyleDelete:cell往右缩进,但是左边出现红色减号控件
UITableViewCellEditingStyleInsert:cell往右缩进,但是左边出现蓝色加号控件
UITableViewCellEditingStyleDelete|UITableViewCellEditingStyleInsert:cell往右缩进,但是左边出现选择控件
*/
return UITableViewCellEditingStyleDelete|UITableViewCellEditingStyleInsert;
}
3.在UITableView的- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath和
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath这两个代理方法中对数据进行操作
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (!tableView.editing) {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
else
{
[self.selectedDataArr addObject:self.dataArr[indexPath.row]];
}
}
-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (tableView.editing) {
[self.selectedDataArr removeObject:self.dataArr[indexPath.row]];
}
}
4.完成选择后的操作,这主要根据需求而定,我在这里做了一个删除操作
//插入数据,刷新界面
NSMutableArray *deleteArr = [NSMutableArray arrayWithCapacity:1];
NSIndexPath *deleteIndexPath = nil;
for (NSString *str in self.selectedDataArr) {
deleteIndexPath = [NSIndexPath indexPathForRow:[self.dataArr indexOfObject:str] inSection:0];
[deleteArr addObject:deleteIndexPath];
}
[self.dataArr removeObjectsInArray:self.selectedDataArr];
[self.selectedDataArr removeAllObjects];
[self.tableView deleteRowsAtIndexPaths:deleteArr withRowAnimation:UITableViewRowAnimationNone];
UITableView cell的移动排序
Simulator Screen Shot 2016年10月16日 下午5.55.06.png Simulator Screen Shot 2016年10月16日 下午5.55.22.pngUITableView cell的排序操作其实和选择操作非常类似,首先也是进入编辑模式,然后在UITableView的- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath的这个代理方法中返回YES,让UITableView可以移动,最后在UITableView的- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath这个代理方法中对排序之后的数据进行操作即可
//设置tableView编辑状态
self.tableView.editing = YES;
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
NSString *exchangeStr = self.dataArr[sourceIndexPath.row];
[self.dataArr removeObjectAtIndex:sourceIndexPath.row];
[self.dataArr insertObject:exchangeStr atIndex:destinationIndexPath.row];
}
UITableView 右滑cell出现多个按钮
Simulator Screen Shot 2016年10月16日 下午11.46.10.pngUITableView 右滑cell出现多个按钮在iOS8之前是不支持的,需要自己去实现,在iOS8以后,UITableView的代理中多了这样一个方法- (nullable NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath和这样一个类UITableViewRowAction,一个UITableViewRowAction对象表示一个按钮,按钮的点击操作包装在UITableViewRowAction创建方法的block中,在代理方法中返回UITableViewRowAction的数组就可以了,最先放入数组的按钮显示在最右侧,最后放入的显示在最左侧。
- (NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath
{
//添加一个删除按钮
UITableViewRowAction *deleteAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"删除" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
//处理数据
[self.dataArr removeObjectAtIndex:indexPath.row];
//更新UI
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
}];
//添加一个上移按钮
UITableViewRowAction *upAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDestructive title:@"上移" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
if (indexPath.row > 0) {
//处理数据
[self.dataArr exchangeObjectAtIndex:indexPath.row withObjectAtIndex:indexPath.row - 1];
//更新UI
[tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:indexPath.row - 1 inSection:indexPath.section]] withRowAnimation:UITableViewRowAnimationNone];
[tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
}
}];
//添加一个下移按钮
UITableViewRowAction *downAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal title:@"下移" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
if (indexPath.row < self.dataArr.count - 1) {
[self.dataArr exchangeObjectAtIndex:indexPath.row withObjectAtIndex:indexPath.row + 1];
//更新UI
[tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
[tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:indexPath.row + 1 inSection:indexPath.section]] withRowAnimation:UITableViewRowAnimationNone];
}
}];
//设置背景颜色
downAction.backgroundColor = [UIColor colorWithRed:(arc4random()%256)/255.0 green:(arc4random()%256)/255.0 blue:(arc4random()%256)/255.0 alpha:1];
//放回数组返回
return @[deleteAction, upAction, downAction];
}
需要注意的是:如果我们自己使用UITableViewRowAction设定了一个或多个按钮,系统自带的删除按钮就失效了。