澳门新葡萄京官网首页 6

iOS文档补完计划–UITableViewDataSource&&UITableViewDelegate

UITbableView作为列表展示信息,除了展示的功能,有时还会用到删除,排序等功能,下面就来讲解一下如何实现排序。

澳门新葡萄京官网首页 1

排序是当表格进入编辑状态后,在单元格的右侧会出现一个按钮,点击按钮,就可以拖动单元格,移动位置,进行手动排序。

目录主要分为以下几个样式:常用、会用、了解

澳门新葡萄京官网首页 2澳门新葡萄京官网首页 3

  • UITableViewDataSource
  • 配置TableView
    • tableView:cellForRowAtIndexPath:
    • tableView:numberOfRowsInSection:
    • numberOfSectionsInTableView:
    • tableView:titleForHeaderInSection:
    • tableView:titleForFooterInSection:
  • 插入&&删除
    • tableView:commitEditingStyle:forRowAtIndexPath:
    • tableView:canEditRowAtIndexPath:
  • 重新排序
    • tableView:canMoveRowAtIndexPath:
    • tableView:moveRowAtIndexPath:toIndexPath:
  • 索引设置
    • sectionIndexTitlesForTableView:
    • tableView:sectionForSectionIndexTitle:atIndex:
  • 澳门新葡萄京官网首页,UITableViewDelegate
  • 配置Row
    • tableView:heightForRowAtIndexPath:
    • tableView:estimatedHeightForRowAtIndexPath:
    • tableView:indentationLevelForRowAtIndexPath:
    • tableView:willDisplayCell:forRowAtIndexPath:
    • tableView:shouldSpringLoadRowAtIndexPath:withContext:
  • 扩展按钮
    • tableView:editActionsForRowAtIndexPath:
    • tableView:accessoryButtonTappedForRowWithIndexPath:
  • 选择管理
    • tableView:willSelectRowAtIndexPath:
    • tableView:didSelectRowAtIndexPath:
    • tableView:willDeselectRowAtIndexPath:
    • tableView:didDeselectRowAtIndexPath:
  • 页眉和页脚iOS11需要注意的新特性
  • 编辑表单
    • tableView:willBeginEditingRowAtIndexPath:
    • tableView:didEndEditingRowAtIndexPath:
    • tableView:editingStyleForRowAtIndexPath:
    • tableView:titleForDeleteConfirmationButtonForRowAtIndexPath:
    • tableView:shouldIndentWhileEditingRowAtIndexPath:
  • 重新排序表单
    • tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath:
  • 移动出可见范围
    • cell/sectionHeaderView/sectionFooterView的消失
  • MENU菜单
  • 高亮管理

使用系统自带拖动排序功能的步骤:

UITableViewDataSource

一个能够为UITableView提供展示要素的代理

1、让tableView进入编辑状态,也就是设置它的editing为YES

2、返回编辑模式,也就是实现UITableViewDelegate中的tableview:editingStyleForRowAtIndexPath:方法,在里面返回UITableViewCellEditingStyleNone模式。如果不实现,默认返回的就是删除模式

3、实现tableView:moveRowAtIndexPath:toIndexPath方法,只要实现该方法,就能实现单元格的拖动排序,但只是实现了表面的排序,并没有修改真实地数据

4、在方法中完成数据模型的更新

配置TableView

  • ##### tableView:cellForRowAtIndexPath:

将返回的Cell插入TableView的indexPath位置。(一旦需要展示cell)则必须实现且不能返回nil。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;

返回的对象通常是重用的cell。

  • ##### – tableView:numberOfRowsInSection:

返回该节有多少行内容(必须实现

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
  • ##### numberOfSectionsInTableView:

返回一共有多少节内容需要展示

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;

默认返回1

  • ##### – tableView:titleForHeaderInSection:

  • ##### – tableView:titleForFooterInSection:

为系统默认样式的sectionHeader/sectionFooter设置文字

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section;

除了敲demo通常没啥用。你应该使用tableView:viewForHeaderInSection:进行自定义样式。

代码:

插入&&删除

  • ##### – tableView:commitEditingStyle:forRowAtIndexPath:

编辑完成时调用

- tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath;

如果点击其他地方被取消、则不会被调用。

editingStyle是一个枚举、有三种可能的值

typedef NS_ENUM(NSInteger, UITableViewCellEditingStyle) { UITableViewCellEditingStyleNone,//没有编辑样式 UITableViewCellEditingStyleDelete,//删除样式  UITableViewCellEditingStyleInsert//插入样式 };

澳门新葡萄京官网首页 4

当你进行了对应的操作(点击了绿色的添加或者红色的删除)、代理将会告知你并让你修改数据源以配合操作。

  • ##### – tableView:canEditRowAtIndexPath:

返回该位置的cell是否可以进入编辑状态

- tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath;

如果没有实现此方法、那么默认所有的cell都可以进入编辑状态。这个编辑状态有两种意思:

  1. 通过[self.tableView setEditing:YES animated:YES];让所有cell进入
  2. 右滑
//  ViewController.m
//  JRTableView删除
//
//  Created by jerehedu on 15/6/11.
//  Copyright (c) 2015年 jerehedu. All rights reserved.
//

#import "ViewController.h"
#import "Goods.h"

@interface ViewController ()<UITableViewDataSource, UITableViewDelegate>

{
    UITableView *_tableView; //列表

    NSMutableArray *_goodsAry; //商品数组

    UIButton *_editBtn; //编辑按钮
}
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    //添加标题
    UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 20, self.view.frame.size.width, 44)];
    titleLabel.text = @"购物车";
    titleLabel.textAlignment = NSTextAlignmentCenter;
    titleLabel.backgroundColor = [UIColor redColor];
    titleLabel.textColor = [UIColor whiteColor];
    [self.view addSubview:titleLabel];

    //添加编辑按钮
    _editBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    _editBtn.frame = CGRectMake(self.view.frame.size.width-60, 25, 50, 34);
    [_editBtn setTitle:@"编辑" forState:UIControlStateNormal];
    [_editBtn setTitle:@"完成" forState:UIControlStateSelected];
    _editBtn.titleLabel.font = [UIFont systemFontOfSize:15];
    _editBtn.backgroundColor = [UIColor colorWithRed:0.8 green:0.8 blue:0.8 alpha:0.5];
    [self.view addSubview:_editBtn];
    [_editBtn addTarget:self action:@selector(clickEditBtn:) forControlEvents:UIControlEventTouchUpInside];

    //添加tableview
    _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 64, self.view.frame.size.width, self.view.frame.size.height-64)];
    _tableView.dataSource = self;
    _tableView.delegate = self;
    [self.view addSubview:_tableView];

    //取数据
    NSArray *ary = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"ShoppingGoodsList" ofType:@"plist"]];

    //把数据存到模型对象中,然后把对象存到数组中
    _goodsAry = [NSMutableArray array];
    for (int i=0; i<ary.count; i++) {
        Goods *good = [Goods goodsWithDic:ary[i]];
        [_goodsAry addObject:good];
    }
}

#pragma mark 数据源  返回有几行
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return _goodsAry.count;
}

#pragma mark 每行显示内容
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *idGood = @"goods";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:idGood];

    if (cell==nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:idGood];
    }

    Goods *good = _goodsAry[indexPath.row];

    cell.imageView.image = [UIImage imageNamed:good.icon];
    cell.textLabel.text = good.name;
    cell.detailTextLabel.text = good.details;
    cell.detailTextLabel.numberOfLines = 6;
    cell.detailTextLabel.textColor = [UIColor brownColor];

    return cell;
}

#pragma mark 选中行
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 取消选中状态
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
}

#pragma mark 设置行高
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 110;
}

#pragma mark 点击编辑按钮
- (IBAction)clickEditBtn:(UIButton *)sender {

    //设置tableview编辑状态
    BOOL flag = !_tableView.editing;
    [_tableView setEditing:flag animated:YES];
    _editBtn.selected = flag;
}

#pragma mark 选择编辑模式,添加模式很少用,默认是删除
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return UITableViewCellEditingStyleNone;
}

#pragma mark 排序 当移动了某一行时候会调用
//编辑状态下,只要实现这个方法,就能实现拖动排序
-(void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
    // 取出要拖动的模型数据
    Goods *goods = _goodsAry[sourceIndexPath.row];
    //删除之前行的数据
    [_goodsAry removeObject:goods];
    // 插入数据到新的位置
    [_goodsAry insertObject:goods atIndex:destinationIndexPath.row];
}

@end

重新排序

让tableView支持拖动、需要以下条件

  1. 让tableView进入编辑状态也就是设置它的editing为YES

  2. 返回编辑模式也就是实现UITableViewDelegate中的tableview:editingStyleForRowAtIndexPath:方法,在里面返回UITableViewCellEditingStyleNone模式。如果不实现,默认返回的就是删除模式

3、实现tableView:moveRowAtIndexPath:toIndexPath方法只要实现该方法,就能实现单元格的拖动排序,但只是实现了表面的排序,并没有修改真实地数据

4、在方法中完成数据模型的更新

  • ##### tableView:canMoveRowAtIndexPath:

是否可以将该cell拖动到指定位

- tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath;

返回该单元格、是否可以被拖动。默认返回YES。

  • ##### – tableView:moveRowAtIndexPath:toIndexPath:

拖动完成时触发、让用户修改数据源

- tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath;

如果不做修改、cell就仅仅是在当前展示上修改了位置。下次被提取或者刷新时会变回原来的顺序。

索引设置

  • ##### – sectionIndexTitlesForTableView:

返回索引数组

- (NSArray<NSString *> *)sectionIndexTitlesForTableView:(UITableView *)tableView;
  1. tablbView的style必须是UITableViewStylePlain
  2. 返回的数组将会悬浮在tableView右侧
  • ##### – tableView:sectionForSectionIndexTitle:atIndex:

点击索引后、将talbeView移动至哪个section处

- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index;

支持数组越界

UITableViewDelegate

对页眉页脚、高度、选择、删除等操作进行支持。

配置Row

  • ##### – tableView:heightForRowAtIndexPath:

可以为指定的行设置高度

- tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;

你可以rowHeight为所有的cell统一设置高度、相对性能较高。而一旦实现heightForRowAtIndexPath方法、你就必须为每一个indexPath设置高度。返回UITableViewAutomaticDimension则由系统自适应计算。

  • ##### – tableView:estimatedHeightForRowAtIndexPath:

返回指定位置的预估行高

- tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath;
  1. 如果没有预估、可以返回UITableViewAutomaticDimension
  2. 使用此功能可以将某些计算、从加载时移动到滚动时进行。以提高性能。
  • ##### – tableView:indentationLevelForRowAtIndexPath:

返回缩进级别

- (NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath;

并不知道有什么地方必须这样用

澳门新葡萄京官网首页 5

  • ##### – tableView:willDisplayCell:forRowAtIndexPath:

某个indexPath的cell将要被绘制

- tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;

由于cellForRow实际上会预创建一些cell、所以cell内部的赋值可以放在这里、以提升一些性能。但是最显著的用途还是对刚展示出来的cell做一些动画吧。比如从右侧一个一个滑入之类。

  • ##### – tableView:shouldSpringLoadRowAtIndexPath:withContext:

cell是否支持iOS11 新特性 Drag and Drop

- tableView:(UITableView *)tableView shouldSpringLoadRowAtIndexPath:(NSIndexPath *)indexPath withContext:(id<UISpringLoadedInteractionContext>)context;
  • ##### – tableView:editActionsForRowAtIndexPath:

自定义左滑事件

- (NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath;

返回一个由UITableViewRowAction组成的数组。他们会响应用对应的点击交互。如果你不实现这个代理、右滑时将会展示默认按钮。

  • ##### – tableView:accessoryButtonTappedForRowWithIndexPath:

当cell的扩展视图被点击时调用

- tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath;

这里的扩展视图指的是cell.accessoryType的视图。如下图所示:

澳门新葡萄京官网首页 6

选择管理

cell被点击时引起的一系列方法调用

需要注意的是即使cell.selectionStyle = UITableViewCellSelectionStyleNone;使得cell跟随点击而改变背景色、以下方法也会被调用。

  • ##### – tableView:willSelectRowAtIndexPath:

将要被选定时触发

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath;

允许你通过返回一个新的NSIndexPath、来修改将要被选择的cell。编辑状态下不会触发此方法

  • ##### – tableView:didSelectRowAtIndexPath:

cell被选定时触发

- tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;

编辑状态下不会触发此方法

  • ##### – tableView:willDeselectRowAtIndexPath:

选中状态被取消时触发

- (NSIndexPath *)tableView:(UITableView *)tableView willDeselectRowAtIndexPath:(NSIndexPath *)indexPath;

如果你返回nil、将不会被取消。允许从定向

  • ##### – tableView:didDeselectRowAtIndexPath:

cell选中被取消时触发

- tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath;

页眉和页脚

//返回页眉和页脚- (nullable UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section; - (nullable UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section; //返回页眉和页脚的高度- tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;- tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section;//页眉和页脚将要展示- tableView:(UITableView *)tableView willDisplayHeaderView:view forSection:(NSInteger)section NS_AVAILABLE_IOS;- tableView:(UITableView *)tableView willDisplayFooterView:view forSection:(NSInteger)section NS_AVAILABLE_IOS;//预估页眉和页脚高度- tableView:(UITableView *)tableView estimatedHeightForHeaderInSection:(NSInteger)section NS_AVAILABLE_IOS;- tableView:(UITableView *)tableView estimatedHeightForFooterInSection:(NSInteger)section NS_AVAILABLE_IOS;

以上的方法通过方法名基本都能理解其用处。

这里需要注意

iOS11之后、系统为我们设置了预估行高。如果只实现了header高度为0.1f、而没有返回具体的view会引起留白的bug。《详见》

编辑表单

要让表单支持左滑

你必须实现commitEditingStyle方法、以告诉tableView左滑操作是由价值的

  • ##### – tableView:willBeginEditingRowAtIndexPath:

表单即将进入编辑模式

- tableView:(UITableView *)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath;
  • ##### -tableView:didEndEditingRowAtIndexPath:

已经离开编辑模式

- tableView:(UITableView *)tableView didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath;

编辑接触触发、并不会记录你执行了哪种操作。所以、你应该在tableView:commitEditingStyle:forRowAtIndexPath:而不是这里实现相关编辑操作。

  • ##### – tableView:editingStyleForRowAtIndexPath:

决定左滑返回哪种附加视图

- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath;

默认返回UITableViewCellEditingStyleDelete

typedef NS_ENUM(NSInteger, UITableViewCellEditingStyle) { UITableViewCellEditingStyleNone,//没有编辑样式 UITableViewCellEditingStyleDelete,//删除样式  UITableViewCellEditingStyleInsert//插入样式 };
  • ##### – tableView:titleForDeleteConfirmationButtonForRowAtIndexPath:

更改UITableViewCellEditingStyleDelete下的文字

- (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath;

setEditing以及左滑时同样有效。

  • ##### – tableView:shouldIndentWhileEditingRowAtIndexPath:

进入编辑模式时、cell背景是否缩进

- tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath;

通知委托在编辑模式下是否需要对表视图指定行进行缩进,NO为关闭缩进,这个方法可以用来去掉move时row前面的空白。

重新排序表单

  • ##### tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath:

在移动cell的时候会多次调用

- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath;

cell的初始位置以及目标。允许对目标位置重定向。移动中的留白动画、以及结果都会受此影响。

移动出可见范围

cell/sectionHeaderView/sectionFooterView的消失

//cell已经移动出可见范围- tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;//sectionHeaderView已经移动出可见范围- tableView:(UITableView *)tableView didEndDisplayingHeaderView:view forSection:(NSInteger)section;//sectionFooterView已经移动出可见范围- tableView:(UITableView *)tableView didEndDisplayingFooterView:view forSection:(NSInteger)section;

MENU菜单

如果想让cell支持menu菜单的呼出、必须将以下三个方法全部实现

  • ##### – tableView:shouldShowMenuForRowAtIndexPath:

长按后是否显示编辑菜单

- tableView:(UITableView *)tableView shouldShowMenuForRowAtIndexPath:(NSIndexPath *)indexPath;
  • ##### – tableView:canPerformAction:forRowAtIndexPath:withSender:

返回该cell支持那种action

- tableView:(UITableView *)tableView canPerformAction:action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:sender;

这个规则你可以参考iOS文档补完计划–UIResponder中关于canPerformAction:withSender:方法的解释。

  • ##### – tableView:performAction:forRowAtIndexPath:withSender:

让代理者对menu操作进行响应

- tableView:(UITableView *)tableView performAction:action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:sender;

高亮管理

高亮权限、高亮、取消高领

//点击时是否高亮。默认YES- tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath;//已经高亮- tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath;//不再高亮- tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath;

最后

本文主要是自己的学习与总结。如果文内存在纰漏、万望留言斧正。如果愿意补充以及不吝赐教小弟会更加感激。

参考资料

官方文档-UITableViewiOS UITableView 的
Plain和Grouped样式的区别iOS_UITableView 编辑(cell的插入, 删除, 移动)ios
tableView那些事 给tableview设置缩进级别关于UITableView委托方法的功能

发表评论

电子邮件地址不会被公开。 必填项已用*标注