你的位置:首页 > 软件开发 > 操作系统 > UITableView学习笔记

UITableView学习笔记

发布时间:2015-08-07 13:00:04
//非原创                                看TableView的资料其实已经蛮久了,一直想写点儿东西,却总是因为各种原因拖延,今天晚上有时间静下心来记录一些最近学习的TableView的知识。下面进入正题,UITableView堪称UIKit里面最 ...

UITableView学习笔记

//非原创

                              

  看TableView的资料其实已经蛮久了,一直想写点儿东西,却总是因为各种原因拖延,今天晚上有时间静下心来记录一些最近学习的TableView的知识。下面进入正题,UITableView堪称UIKit里面最复杂的一个控件了,使用起来不算难,但是要用好并不容易。当使用的时候我们必须要考虑到后台数据的设计,tableViewCell的设计和重用以及tableView的效率等问题。

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

一、UITableView概述

  UITableView继承自UIScrollView,可以表现为Plain和Grouped两种风格,分别如下图所示:

      UITableView学习笔记        UITableView学习笔记

  其中左边的是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。 

  UITableViewController默认的会在viewWillAppear的时候,清空所有选中cell,我们可以通过设置self.clearsSelectionOnViewWillAppear = NO,来禁用该功能,并在viewDidAppear中调用UIScrollView的flashScrollIndicators方法让滚动条闪动一次,从而提示用户该控件是可以滑动的。 

 

三、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;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{  NSArray *sections = [SvTableViewDataModal sections];  SvSectionModal *sectionModal = [sections objectAtIndex:indexPath.section];    static NSString *reuseIdetify = @"SvTableViewCell";  UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdetify];  if (!cell) {    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdetify];    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;    cell.showsReorderControl = YES;        for (int i = 0; i < 6; ++i) {      UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(100 + 15 * i, 0, 30, 20)];      label.backgroundColor = [UIColor redColor];      label.text = [NSString stringWithFormat:@"%d", i];      [cell.contentView addSubview:label];      [label release];    }  }    cell.textLabel.backgroundColor = [UIColor clearColor];  cell.textLabel.text = [sectionModal.cityNames objectAtIndex:indexPath.row];  return cell;} 
UITableView学习笔记

  在上面这个例子中,我往每个cell中添加了6个subView,而且每个subView都是半透明(UIView默认是半透明的),这个时候滑动起来明显就可以感觉到有点颤抖,不是很流畅。当把每一个subView的opaque属性设置成YES的时候,滑动会比之前流畅一些,不过还是有点儿卡。

  2、从UITableViewCell派生一个类

  通过从UITableViewCell中派生一个类,可以更深度的定制一个cell,可以指定cell在进入edit模式的时候如何相应等等。最简单的实现方式就是将所有要绘制的内容放到一个定制的subView中,并且重载该subView的drawRect方法直接把要显示的内容绘制出来(这样可以避免subView过多导致的性能瓶颈),最后再将该subView添加到cell派生类中的contentView中即可。但是这样定制的cell需要注意在数据改变的时候,通过手动调用该subView的setNeedDisplay方法来刷新界面,这个例子可以在苹果的帮助文档中的TableViewSuite工程中找到,这儿就不举例了。

  观看这两种定制cell的方法,我们会发现subView都是添加在cell的contentView上面的,而不是直接加到cell上面,这样写也是有原因的。下面我们看一下cell在正常状态下和编辑状态下的构成图:

  cell在正常状态下的构成图如下:

UITableView学习笔记

  进入编辑状态下cell的构成图如下:

UITableView学习笔记

  通过观察上面两幅图片我们可以看出来,当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流程图:

UITableView学习笔记

  上图中当tableView进入到edit模式的时候,tableView会去对当前可见的cell逐个调用dataSource的tableView:canMoveRowAtIndexPath:方法(此处官方给出的流程图有点儿问题),决定当前cell是否显示reoedering控件,当开始进入拖动cell进行拖动的时候,每滑动过一个cell的时候,会去掉用delegate的tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath:方法,去判断当前划过的cell位置是否可以被替换,如果不行则给出建议的位置。当用户放手时本次reordering操作结束,调用dataSource中的tableView:moveRowAtIndexPath:toIndexPath:方法更新tableView对应的数据。

  此处给个我写demo中的更新数据的小例子:

UITableView学习笔记
#pragma mark -- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{  NSLog(@"commit editStyle: %d", editingStyle);    if (editingStyle == UITableViewCellEditingStyleDelete) {    NSArray *sections = [SvTableViewDataModal sections];    SvSectionModal *sourceSectionModal = [sections objectAtIndex:indexPath.section];    [sourceSectionModal.cityNames removeObjectAtIndex:indexPath.row];        [SvTableViewDataModal replaceSectionAtIndex:indexPath.section withSection:sourceSectionModal];    [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationRight];  }  else {    // do something for add it    NSArray *sections = [SvTableViewDataModal sections];    SvSectionModal *sourceSectionModal = [sections objectAtIndex:indexPath.section];    [sourceSectionModal.cityNames insertObject:@"new City" atIndex:indexPath.row];    [SvTableViewDataModal replaceSectionAtIndex:indexPath.section withSection:sourceSectionModal];        [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationRight];  }}
UITableView学习笔记

  代码中首先判断当前操作是delete操作还是insert操作,相应的更新数据,最后根据情况调用tableView的insertRowsAtIndexPaths:withRowAnimation:或者deleteRowsAtIndexPaths:withRowAnimation:方法,对tableView的视图进行更新。cell的删除和添加操作相对还是比较简单的。

 

六、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:方法。

  

七、批量插入,删除,部分更新操作

  UITableView提供了一个批量操作的特性,这个功能在一次进行多个row或者scetion的删除,插入,获取更新多个cell内容的时候特别好用。所有的批量操作需要包含在beginUpdates和endUpdates块中,否则会出现异常。

  下面请看我demo中的一个批量操作的例子:

UITableView学习笔记

原标题:UITableView学习笔记

关键词:ie

ie
*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: admin#shaoqun.com (#换成@)。