UITableView的介绍及使用

前言

UITableView堪称UIKit里面最复杂的一个控件了,使用起来不算难,但是要用好并不容易。当使用的时候我们必须要考虑到后台数据的设计,tableViewCell的设计和重用以及tableView的效率等问题。

下面分9个方面进行介绍:

一、UITableView概述

  • UITableView继承自UIScrollView,可以表现为Plain和Grouped两种风格。
  • 查看UITableView的帮助文档我们会注意到UITableView有两个Delegate分别为:dataSource和delegate。
  • dataSource是UITableViewDataSource类型,主要为UITableView提供显示用的数据(UITableViewCell),指定UITableViewCell支持的编辑操作类型(insert,delete和reordering),并根据用户的操作进行相应的数据更新操作,如果数据没有更具操作进行正确的更新,可能会导致显示异常,甚至crush。
  • delegate是UITableViewDelegate类型,主要提供一些可选的方法,用来控制tableView的选择、指定section的头和尾的显示以及协助完成cell的删除和排序等功能。
  • 提到UITableView,就必须的说一说NSIndexPath。UITableView声明了一个NSIndexPath的类别,主要用来标识当前cell的在tableView中的位置,该类别有section和row两个属性,前者标识当前cell处于第几个section中,后者代表在该section中的第几行。
  • UITableView只能有一列数据(cell),且只支持纵向滑动,当创建好的tablView第一次显示的时候,我们需要调用其reloadData方法,强制刷新一次,从而使tableView的数据更新到最新状态。

二、UITableViewController简介

  • UITableViewController是系统提供的一个便利类,主要是为了方便我们使用UITableView,该类生成的时候就将自身设置成了其包含的tableView的dataSource和delegate,并创建了很多代理函数的框架,为我们大大的节省了时间,我们可以通过其tableView属性获取该controller内部维护的tableView对象。默认情况下使用UITableViewController创建的tableView是充满全屏的,如果需要用到tableView是不充满全屏的话,我们应该使用UIViewController自己创建和维护tableView。
  • UITableViewController提供一个初始化函数initWithStyle:,根据需要我们可以创建Plain或者Grouped类型的tableView,当我们使用其从UIViewController继承来的init初始化函数的时候,默认将会我们创建一个Plain类型的tableView。

三、UITableViewCell介绍

  • UITableView中显示的每一个单元都是一个UITableViewCell对象,看文档的话我们会发现其初始化函数initWithStyle:reuseIdentifier:比较特别,跟我们平时看到的UIView的初始化函数不同。这个主要是为了效率考虑,因为在tableView快速滑动的滑动的过程中,频繁的alloc对象是比较费时的,于是引入了cell的重用机制,这个也是我们在dataSource中要重点注意的地方,用好重用机制会让我们的tableView滑动起来更加流畅。
  • 我们可以通过cell的selectionStyle属性指定cell选中时的显示风格,以及通过accessoryType来指定cell右边的显示的内容,或者直接指定accessoryView来定制右边显示的view。
  • 系统提供的UITableView也包含了四种风格的布局,分别是:
  • typedef enum {
    UITableViewCellStyleDefault,
    UITableViewCellStyleValue1,
    UITableViewCellStyleValue2,
    UITableViewCellStyleSubtitle
    } UITableViewCellStyle;

    这几种文档中都有详细描述,这儿就不在累赘。然而可以想象系统提供的只是最常用的几种类型,当系统提供的风格不符合我们需要的时候,我们就需要对cell进行定制了,有以下两种定制方式可选:
1、直接向cell的contentView上面添加subView
  • 这是比较简单的一种的,根据布局需要我们可以在不同的位置添加subView。但是此处需要注意:所有添加的subView都最好设置为不透明的,因为如果subView是半透明的话,view图层的叠加将会花费一定的时间,这会严重影响到效率。同时如果每个cell上面添加的subView个数过多的话(通常超过3,4个),效率也会受到比较大的影响
2、从UITableViewCell派生一个类
  • 通过从UITableViewCell中派生一个类,可以更深度的定制一个cell,可以指定cell在进入edit模式的时候如何响应等等。最简单的实现方式就是将所有要绘制的内容放到一个定制的subView中,并且重载该subView的drawRect方法直接把要显示的内容绘制出来(这样可以避免subView过多导致的性能瓶颈),最后再将该subView添加到cell派生类中的contentView中即可。但是这样定制的cell需要注意在数据改变的时候,通过手动调用该subView的setNeedDisplay方法来刷新界面,这个例子可以在苹果的帮助文档中的TableViewSuite工程中找到,这儿就不举例了。
  •  观看这两种定制cell的方法,我们会发现subView都是添加在cell的contentView上面的,而不是直接加到cell上面,这样写也是有原因的。下面我们看一下cell在正常状态下和编辑状态下的构成图:
    cell在正常状态下的构成图如下:
    这里写图片描述
    进入编辑状态下cell的构成图如下:
    这里写图片描述

  • 通过观察上面两幅图片我们可以看出来,当cell在进入编辑状态的时候,contentView会自动的缩放来给Editing control腾出位置。这也就是说如果我们把subView添加到contentView上,如果设置autoresizingMask为更具父view自动缩放的话,cell默认的机制会帮我们处理进入编辑状态的情况。而且在tableView是Grouped样式的时候,会为cell设置一个背景色,如果我们直接添加在cell上面的话,就需要自己考虑到这个背景色的显示问题,如果添加到contentView上,则可以通过view的叠加帮助我们完成该任务。综上,subView最好还是添加到cell的contentView中。

四、Reordering

  • 为了使UITableVeiew进入edit模式以后,如果该cell支持reordering的话,reordering控件就会临时的把accessaryView覆盖掉。为了显示reordering控件,我们必须将cell的showsReorderControl属性设置成YES,同时实现dataSource中的tableView:moveRowAtIndexPath:toIndexPath:方法。我们还可以同时通过实现dataSource中的 tableView:canMoveRowAtIndexPath:返回NO,来禁用某一些cell的reordering功能。下面看苹果官方的一个reordering流程图
    这里写图片描述
  • 上图中当tableView进入到edit模式的时候,tableView会去对当前可见的cell逐个调用dataSource的tableView:canMoveRowAtIndexPath:方法(此处官方给出的流程图有点儿问题),决定当前cell是否显示reoedering控件,当开始进入拖动cell进行拖动的时候,每滑动过一个cell的时候,会去掉用delegate的tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath:方法,去判断当前划过的cell位置是否可以被替换,如果不行则给出建议的位置。当用户放手时本次reordering操作结束,调用dataSource中的tableView:moveRowAtIndexPath:toIndexPath:方法更新tableView对应的数据。

五、Delete & Insert

  • cell的delete和insert操作大部分流程都是一样的,当进入编辑模式的时候具体的显示是delete还是insert取决与该cell的editingStyle的值,editStyle的定义如下:
typedef enum {
    UITableViewCellEditingStyleNone,
    UITableViewCellEditingStyleDelete,
    UITableViewCellEditingStyleInsert
} UITableViewCellEditingStyle;
  • 当tableView进入编辑模式以后,cell上面显示的delete还是insert除了跟cell的editStyle有关,还与 tableView的delegate的tableView:editingStyleForRowAtIndexPath:方法的返回值有关(在这里唠叨一句,其实delegate提供了很多改变cell属性的机会,如非必要,还是不要去实现这些方法,因为执行这些方法也造成一定的开销)。
      delete和insert的流程如下苹果官方文档中给出的图所示
       这里写图片描述

六、Cell的Select操作

  • 当我们在tableView中点击一个cell的时候,将会调用tableView的delegate中的tableView:didSelectRowAtIndexPath:方法。

      关于tableView的cell的选中,苹果官方有以下几个建议:

      1、不要使用selection来表明cell的选择状态,而应该使用accessaryView中的checkMark或者自定义accessaryView来显示选中状态。

      2、当选中一个cell的时候,你应该取消前一个cell的选中。

      3、如果cell选中的时候,进入下一级viewCOntroller,你应该在该级菜单从navigationStack上弹出的时候,取消该cell的选中。

  • 这块儿再提一点,当一个cell的accessaryType为UITableViewCellAccessoryDisclosureIndicator的时候,点击该accessary区域通常会将消息继续向下传递,即跟点击cell的其他区域一样,将会掉delegate的tableView:didSelectRowAtIndexPath:方法,当时如果accessaryView为 UITableViewCellAccessoryDetailDisclosureButton的时候,点击accessaryView将会调用delegate的 tableView:accessoryButtonTappedForRowWithIndexPath:方法。

七、IndexList

  • 当我们tableView中section有很多,数据量比较大的时候我们可以引入indexList,来方便完成section的定位,例如系统的通讯录程序。我们可以通过设置tableView的sectionIndexMinimumDisplayRowCount属性来指定当tableView中多少行的时候开始显示IndexList,默认的设置是NSIntegerMax,即默认是不显示indexList的。
    为了能够使用indexlist我们还需要实现dataSource中一下两个方法:
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView; 
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index; 

第一个方法返回用于显示在indexList中的内容的数组,通常为A,B,C…Z。第二个方法的主要作用是根据用户在indexList中点击的位置,返回相应的section的index值。这个例子可以在苹果官方给出的TableViewSuite中找到,实现起来还是很简单的。

八、其他

  • 1、分割线
    我们可以通过设置tableView的separatorStyle属性来设置有无分割线以及分割线的风格,同时还可以通过tableView的separatorColor属性来设置分割线的颜色,其中style定义如下:
typedef enum {
    UITableViewCellSeparatorStyleNone,
    UITableViewCellSeparatorStyleSingleLine,
    UITableViewCellSeparatorStyleSingleLineEtched
} UITableViewCellSeparatorStyle;
  • 2、如何提高tableView的性能
    a、重用cell,我们都知道申请内存是需要时间,特别是在一段时间内频繁的申请内存将会造成很大的开销,而且上tebleView中cell大部分情况下布局都是一样的,这个时候我们可以通过回收重用机制来提高性能。

      b、避免content的重新布局,尽量避免在重用cell时候,对cell的重新布局,一般情况在在创建cell的时候就将cell布局好。

      c、使用不透明的subView,在定制cell的时候,将要添加的subView设置成不透明的会大大减少多个view层叠加时渲染所需要的时间。

      d、如果方便,直接重载subView的drawRect方法,如果定制cell的过程中需要多个小的元素的话,最好直接对要显示的多个项目进行绘制,而不是采用添加多个subView。

      e、tableView的delegate的方法如非必要,尽量不要实现tableView的delegate中的很多函数提供了对cell属性的进一步控制,比如每个cell的高度,cell是否可以编辑,支持的edit风格等,如非必要最好不要实现这些方法因为快速的调用这些方法也会影响性能。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值