主要实现了 UITableView 的各种编辑状态,先看效果吧:
很详细的系统编辑,我写的不一定好使,但必须要掌握系统编辑!看图:
从 iOS8 开始系统侧滑删除支持多个按钮形式,目前我们还需要兼容 iOS6 ,所以我选择 SWTableViewCell 来做侧滑删除;但是使用 Instrument 检测发现,SW 有性能问题;我的列表本可以更加流畅,但是每次滑动 cell,都需要更新侧滑按钮,即使没有显示出来!SW 创建了按钮之后还要重新布局,这些都会引起性能上的消耗,系统的侧滑高明之处在于侧滑 view 是懒加载的,只有在侧滑的时候才加载,不用的时候就会被删除...
由于使用 SW 做懒加载不太好实现,SW 侧滑的时候存在bug等原因;因此我尝试改造 iOS8 系统之前的侧滑,为了使用方便,因此封装了一套和系统一样的 API ,点击按钮的事件和 iOS8 系统原生的一样,采用 block 回调方式...
最终实现了,iOS8之后 完全使用系统的,之前版本则使用改造的,这与 SW 相比,使用方式不复杂(都需要继承),并且性能上不存在问题(完全使用懒加载形式,仅当侧滑时才配置侧滑菜单按钮)...
SW 性能问题:
使用方法:
与 iOS8 系统原生API一样,就是把 UITableViewRowAction 改为 QLTableViewRowAction 就行了;
- (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath
{
QLTableViewRowAction *action1 = [QLTableViewRowAction rowActionWithStyle:QLTableViewRowActionStyleDefault title:@"1自动删除" handler:^(QLTableViewRowAction *action, NSIndexPath *indexPath) {
//handle your click event
}];
QLTableViewRowAction *action2 = [QLTableViewRowAction rowActionWithStyle:QLTableViewRowActionStyleDefault title:@"2自删除" handler:^(QLTableViewRowAction *action, NSIndexPath *indexPath) {
//handle your click event
}];
QLTableViewRowAction *action3 = [QLTableViewRowAction rowActionWithStyle:QLTableViewRowActionStyleNormal title:@"3删除" handler:^(QLTableViewRowAction *action, NSIndexPath *indexPath) {
//handle your click event
}];
QLTableViewRowAction *action4 = [QLTableViewRowAction rowActionWithStyle:QLTableViewRowActionStyleNormal title:@"4不删除" handler:^(QLTableViewRowAction *action, NSIndexPath *indexPath) {
//handle your click event
}];
NSArray *bgColors = @[[UIColor colorWithRed:255.0f/255.0f green:59.0f/255.0f blue:48.0f/255.0f alpha:1.0],
[UIColor colorWithRed:255.0f/255.0f green:156.0f/255.0f blue:3.0f/255.0f alpha:1.0],
[UIColor colorWithRed:255.0f/255.0f green:128.0f/255.0f blue:1.0f/255.0f alpha:1.0]];
//configure bg color
action2.backgroundColor = bgColors[1];
action3.backgroundColor = bgColors[1];
action4.backgroundColor = bgColors[2];
if (indexPath.row == 0) {
return @[action1];
}else if (indexPath.row == 1){
return @[action1,action2];
}else if (indexPath.row == 2){
return @[action1,action2,action3];
}
return @[action1,action2,action3,action4];
}
主要使用了系统的特性,系统 cell 是支持向右缩进的;核心代码:
cell.indentationLevel = model.leval;
cell.indentationWidth = 10 * cell.indentationLevel;
思路是把 cell 的 indentationLevel 记录在对应的 model 里;下一个层级 cell 的 indentationLevel 比当前层级大 1;这样就会自动偏移;
PS: 如果自定义 cell 的话,控件的 x 坐标记得是 ** indentationWidth ** 才能偏移!
理解一下属性的含义:
//正常情况下的选择,不影响编辑状态!
/*
是否允许选中;不会影响 allowsMultipleSelection;即使这个为NO,也可以多选!
*/
self.tableView.allowsSelection = NO;
/*
是否允许正常情况下多选;允许时,可通过这个属性获取选择的cell;
tableView.indexPathsForSelectedRows
*/
self.tableView.allowsMultipleSelection = NO;
//编辑情况下的选择,不影响正常状态!
/*
编辑的时候是否允许单选选中,允许时点击cell会触发:didSelectRowAtIndexPath 代理方法;
仅仅在这3种模式下生效:
UITableViewCellEditingStyleNone,
UITableViewCellEditingStyleDelete,
UITableViewCellEditingStyleInsert
如果使用 UITableViewCellEditingStyleDelete | UITableViewCellEditingStyleInsert;则没用,因为这属于多选!
*/
self.tableView.allowsSelectionDuringEditing = YES;
/*
这个属性意味着要不要开启多选!开启多选后,点击编辑完成处理选中的cell!
如果开启,就会忽略 editingStyleForRowAtIndexPath 代理方法;
不开启,就会去调用这个代理方法;
PS:还有一种开启多选的方法就是在 editingStyleForRowAtIndexPath 代理方法里返回 UITableViewCellEditingStyleDelete | UITableViewCellEditingStyleInsert;不过 allowsMultipleSelectionDuringEditing 还是 NO,不会变为YES!
*/
self.tableView.allowsMultipleSelectionDuringEditing = YES;
/**
* 侧滑是编辑的另一种形式,出现侧滑删除的条件:
1. canEditRowAtIndexPath 为 YES;
2. editingStyleForRowAtIndexPath 返回 UITableViewCellEditingStyleDelete;
3. 实现 commitEditingStyle 方法;
*
*/
/*
//默认是 UITableViewCellEditingStyleDelete;
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewCellEditingStyleDelete;
}
//默认是YES
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
*/
//删除,插入,侧滑都会调用此方法;iOS8侧滑除外!多选不会触发这个方法!
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
}
//重写这个方法,处理多选处理!
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
[super setEditing:editing animated:animated];
NSLog(@"---%d",self.tableView.allowsMultipleSelectionDuringEditing);
}
有的时候项目里需要同时支持多选编辑和侧滑删除,在清楚了多选编辑的实现和侧滑的封装使用逻辑之后,这里很容易把他们整合到一起,基本都是系统的方法:
//开启多选编辑
- 1.self.tableView.allowsMultipleSelectionDuringEditing = YES;
- 2.cell 必须继承 QLTableViewCell;
- 3.实现这个方法;一般就是个空实现而已;
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { //nothing,just show delete; }
- 4.实现这个方法;不需要改动,这样复制就行了;
- (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath { NSArray *actions = [self tableView:tableView editActionsForRowAtIndexPath:indexPath]; NSArray *titles = [actions valueForKeyPath:@"title"]; return [titles componentsJoinedByString:@"拼接"]; }
上面4就实现了多选和侧滑删除;接下来配置支持的侧滑删除项以及处理回调;
//兼容 iOS8 和 之前版本;
- (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath
{
QLTableViewRowAction *action1 = [QLTableViewRowAction rowActionWithStyle:QLTableViewRowActionStyleDefault title:@"1取消" handler:^(QLTableViewRowAction *action, NSIndexPath *indexPath) {
NSLog(@"%@",action.title);
[self setEditing:NO animated:NO];
}];
QLTableViewRowAction *action2 = [QLTableViewRowAction rowActionWithStyle:QLTableViewRowActionStyleNormal title:@"2删除" handler:^(QLTableViewRowAction *action, NSIndexPath *indexPath) {
NSLog(@"%@",action.title);
NSObject *obj = [self.objects objectAtIndex:indexPath.row];
[self.objects removeObject:obj];
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationBottom];
[tableView endUpdates];
}];
QLTableViewRowAction *action3 = [QLTableViewRowAction rowActionWithStyle:QLTableViewRowActionStyleNormal title:@"3置顶" handler:^(QLTableViewRowAction *action, NSIndexPath *indexPath) {
NSLog(@"%@",action.title);
NSObject *obj = [self.objects objectAtIndex:indexPath.row];
[self.objects removeObjectAtIndex:indexPath.row];
[self.objects insertObject:obj atIndex:0];
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];
[tableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:0 inSection:0]] withRowAnimation:UITableViewRowAnimationTop];
[tableView endUpdates];
}];
QLTableViewRowAction *action4 = [QLTableViewRowAction rowActionWithStyle:QLTableViewRowActionStyleNormal title:@"4没实现" handler:^(QLTableViewRowAction *action, NSIndexPath *indexPath) {
NSLog(@"%@",action.title);
}];
NSArray *bgColors = @[[UIColor colorWithRed:255.0f/255.0f green:156.0f/255.0f blue:3.0f/255.0f alpha:1.0],
[UIColor colorWithRed:255.0f/255.0f green:128.0f/255.0f blue:1.0f/255.0f alpha:1.0]];
action3.backgroundColor = bgColors[0];
action4.backgroundColor = bgColors[1];
if (indexPath.row == 0) {
return @[action1];
}else if (indexPath.row == 1){
return @[action1,action2];
}else if (indexPath.row == 2){
return @[action1,action2,action3];
}
return @[action1,action2,action3,action4];
}
处理多选编辑逻辑:
//重写这个方法,处理多选处理!
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
if (!editing) {
NSArray *idxs = self.tableView.indexPathsForSelectedRows;
if (!idxs) {
[super setEditing:editing animated:YES & animated];
}else{
[super setEditing:editing animated:NO];
NSMutableArray *objs = [NSMutableArray array];
for (NSIndexPath *idx in idxs) {
NSObject *obj = [self.objects objectAtIndex:idx.row];
[objs addObject:obj];
}
[self.objects removeObjectsInArray:objs];
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:idxs withRowAnimation:UITableViewRowAnimationLeft];
[self.tableView endUpdates];
}
}else{
[super setEditing:editing animated:animated];
}
}