UITableView,你了解多少?

2020-02-07 10:44栏目:竞技宝app
TAG:

最近我总算把UITableView弄透彻了,以前自认为很熟,其实还是没有深入了解。于是我总结了一些相关的问题,这些问题并不是冷门和偏门,而是非常实用的技术。很多人就算有一年经验了,因为不得其法,走了弯路,实现是实现了,但解决办法太山寨。1.一个UITableViewCell如何得到它的宿主UITableView对象?IOS7上他们的层次结构发生了什么变化?2.一个UITableView上有多个cell,那么除了你可以自定义cell以外,还有哪些内容是可以自定义的。这里友情提醒一下,还有表头可以自定义。那么,还有哪些呢?需要您再补充三个。3.UITableViewCell在ios6以及以前的版本上透明太容易了,那么在IOS7上如何透明?网上目前没有找到合适的方法,我原创了一种!4.如何通过代码直接滑到UITableView的底部?代码虽然一行可以搞定,但要给出这个代码的第二个参数,这是关键。5.UITableView如何获取不可视的所有UITableViewCell对象?6.UITableView如何获取可视的所有UITableViewCell对象?7.在什么情况下-(void)tableView:(UITableView*)tableViewdidSelectRowAtIndexPath:(NSIndexPath*)indexPath{这个事件不会执行。此时应该如何解决cell的单击响应?8.如何让UITableViewCell响应单击事件,而又不出现单击时的按下效果?9.对于分组UITableView,如何改变组与组之间的间距。10.由xib加载自定义UITableViewCell的时候,如何让cell复用?这个看似简单,很多人不进行实际操作是无法休会到xib复用的。有些人为了解决这个麻烦,直接用纯代码在UITableViewCell上创建控件达到自定义的效果。纯代码控制复用好弄些,但纯代码画出来的cell可读性差,没有用xib设计出来的直观和设计时的高效,也不便于后期维护。所以,这个问题是如何让xib创建的cell复用?所谓复用,就是cell在滑出屏幕的时候不释放,再滑入屏幕的时候不重绘。注意用retain是没有效果的。如果你能在短时间内给出所有问题的答案,那你就真是熟悉UITableView了。以上十个问题的答案,我相信先后会有一些人答出一部分,我会在贴子满3页后,相继给出大家没有回答上来的问题的答案。这里欢迎大家一起交流学习。QQ群37204383

前言:####

对于搞IOS开发的只要提起UITableView这个控件,我想没人会说他不了解吧,以为这个控件太基本太核心太好用了,因此我们必须熟练掌握它的使用,以下文章中我会从最基本的UITableView的使用直到UITableView数据源的分离,讲述我对UITableView的理解,废话不多说开撸。

前言

    NS_CLASS_AVAILABLE_IOS(2_0) @interface UITableView : UIScrollView <NSCoding>
    @available(iOS 2.0, *)       public class UITableView : UIScrollView, NSCoding
流程:####
  • 纯代码实现一个UITableView
  • TableViewCell 重复利用
  • UITableViewCell的多种创建方式

1、tableView 的创建

  • Objective-C

    • 遵守 UITableViewDelegate, UITableViewDataSource 协议

    • 数据源 初始化

          // 声明数据源,必须声明为全局变量
          @property(nonatomic, retain)NSMutableArray *myDataArray;
      
          // 数据源数组初始化,定义一个可变数组做为表格的数据源
          myDataArray = [[NSMutableArray alloc] init];
      
          NSArray *array1 = @[@"UIWindow", @"UIApplication", @"UIView", @"UILabel", 
                              @"UIProgressView", @"UIAlertView", @"UIActionSheet", @"UIPickerView"];
          NSArray *array2 = @[@"窗口", @"应用", @"视图", @"标签", @"进度条", @"警告框", 
                              @"操作表", @"选择框", @"风火轮", @"图像视图", @"网页视图", @"滚动视图", 
                              @"多行文本视图"];
      
          // 向数据源中添加数据
          [myDataArray addObject:array1];
          [myDataArray addObject:array2];
      
    • tableView 初始化

          // 声明表格视图对象,头标题和脚标题悬浮显示,默认类型
          UITableView *myTableView = [[UITableView alloc] initWithFrame:self.view.bounds];
      
          // 设置 tableView 的代理
          myTableView.delegate = self;
          myTableView.dataSource = self;
      
          // 将 tableView 添加到窗口中
          [self.view addSubview:myTableView];
      
    • 协议方法

          // 设置分段数
          - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
      
              // 数据源数组为多维数组时,用数组计算
              return myDataArray.count;
          }
      
          // 设置行数
          - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
      
              // section 段,返回每段中有多少行
              return [[myDataArray objectAtIndex:section] count];
          }
      
          // 设置每一行显示的内容
          - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
      
              // 创建标识词,随意设置,但不能和其它 tableView 的相同
              static NSString *indentifier = @"testIdentifier";
      
              // 根据标志词先从复用队列里查找
              UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:indentifier];
      
              // 复用队列中没有时再创建
              if (cell == nil) {
      
                  // 创建新的 cell,默认为主标题模式
                  cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:indentifier];
              }
      
              // 设置每一行显示的文字内容
              cell.textLabel.text = [[myDataArray objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
      
              // indexPath.section 分段数,indexPath.row 行数,设置图片内容,图片在 Cell 的左端,图片大小自动压缩
              cell.imageView.image = [UIImage imageNamed:@"HQ_0003"];
      
              return cell;
          }
      
  • Swift

    • 遵守 UITableViewDelegate, UITableViewDataSource 协议

    • 数据源 初始化

          // 声明数据源,必须声明为全局变量
          var myDataArray:[[String]] = Array()
      
          let array1:[String] = ["UIWindow", "UIApplication", "UIView", "UILabel", "UIProgressView", 
                                "UIAlertView", "UIActionSheet", "UIPickerView"]
          let array2:[String] = ["窗口", "应用", "视图", "标签", "进度条", "警告框", "操作表", "选择框", 
                                "风火轮", "图像视图", "网页视图", "滚动视图", "多行文本视图", "工具条"]
      
          // 向数据源中添加数据
          myDataArray.append(array1)
          myDataArray.append(array2)
      
    • tableView 初始化

          // 声明表格视图对象,头标题和脚标题悬浮显示,默认类型
          let myTableView:UITableView = UITableView(frame: self.view.bounds)
      
          // 设置 tableView 的代理
          myTableView.delegate = self
          myTableView.dataSource = self
      
          // 将 tableView 添加到窗口中
          self.view.addSubview(myTableView)
      
    • 协议方法

          // 设置分段数
          func numberOfSectionsInTableView(tableView: UITableView) -> Int {
      
              // 数据源数组为多维数组时,用数组计算
              return myDataArray.count
          }
      
          // 设置行数
          func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
      
              // section 段,返回每段中有多少行
              return myDataArray[section].count
          }
      
          // 设置每一行显示的内容
          func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
      
              // 创建标识词,随意设置,但不能和其它 tableView 的相同
              let indentifier = "testIdentifier"
      
              // 根据标志词先从复用队列里查找
              var cell = tableView.dequeueReusableCellWithIdentifier(indentifier)
      
              // 复用队列中没有时再创建
              if cell == nil {
      
                  // 创建新的 cell,默认为主标题模式
                  cell = UITableViewCell(style: .Default, reuseIdentifier: indentifier)
              }
      
              // 设置每一行显示的文字内容
              cell!.textLabel?.text = myDataArray[indexPath.section][indexPath.row]
      
              // indexPath.section 分段数,indexPath.row 行数,设置图片内容,图片在 Cell 的左端,图片大小自动压缩
              cell!.imageView?.image = UIImage(named: "HQ_0003")
      
              return cell!
          }
      
纯代码实现一个UITableView####
#import "ViewController.h"

// 使用tableView UITableViewDataSource 必须实现,有了他tableView对象才能拿到自己想要的数据
@interface ViewController () <UITableViewDataSource>

@property (nonatomic, strong) UITableView *tableView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    [self.view addSubview:self.tableView];
}

/**
 *  通过懒加载方式创建tableView对象
 *
 *  @return tableView对象
 */
- (UITableView *)tableView
{
    if (!_tableView) {
        _tableView = [[UITableView alloc]init];
        CGSize SCREEN_SIZE = [UIScreen mainScreen].bounds.size;
        CGFloat tableViewX = 0;
        CGFloat tableViewY = 64;
        CGFloat tableViewWidth = SCREEN_SIZE.width;
        CGFloat tableViewHeight = SCREEN_SIZE.height-tableViewY;
        CGRect tableRect = CGRectMake(tableViewX, tableViewY, tableViewWidth, tableViewHeight);
        _tableView.frame = tableRect;
        _tableView.dataSource = self;
    }
    return _tableView;
}

// tableView 的代理,用来告诉tableView共有多少条数据Cell(这个代理是强制性的,必须实现)
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 10;
}

// tableView 的代理,用来告诉tableView每个cell都长什么样子(这个代理是强制性的,必须实现)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [[UITableViewCell alloc]init];
    cell.textLabel.text = @"tableView测试";
    return cell;
}

效果图:

图片 1

效果图

2、tableView 的设置

  • Objective-C

    • 设置数据源初始化方式

          // 将数组指向新的空间,可以不提前申请空间(不初始化)
          myDataArray = @[array1, array2];
      
          // 将数组里的所有数据替换成新的,必须提前申请空间
          myDataArray.array = @[array1, array2];
      
    • 设置分段的头标题和脚标题

          // 设置分段的头标题和脚标题的类型
          /*
              UITableViewStylePlain,     // 简单模式,每个分段之间紧密连接,头脚标题悬浮显示,默认类型
              UITableViewStyleGrouped    // 分组模式,每个分段之间分开,头脚标题跟随移动,头标题英文自动大写
          */
      
              // 头标题和脚标题悬浮显示,默认类型
              UITableView *myTableView = [[UITableView alloc] init];
      
              UITableView *myTableView = [[UITableView alloc] initWithFrame:frame];
      
              // 带显示类型的设置
              UITableView *myTableView = [[UITableView alloc] initWithFrame:frame style:UITableViewStyleGrouped];
      
          // 设置分段的头标题高度,UITableViewDelegate 协议方法
          - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
      
              return 40;
          }
      
          // 设置分段的脚标题高度,UITableViewDelegate 协议方法
          - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
      
              return 30;
          }
      
          // 设置分段的头标题内容,UITableViewDataSource 协议方法
          - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
      
              if (0 == section) {
                  return @"English Header";
              }
              else {
                  return @"中文 Header";
              }
          }
      
          // 设置分段的脚标题内容,UITableViewDataSource 协议方法
          - (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
      
              if (0 == section) {
                  return @"English Footer";
              }
              else {
                  return @"中文 Footer";
              }
          }
      
          // 分段头标题视图,UITableViewDelegate 协议方法,返回自定义的标题视图
          - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
      
              if (!section) {
                  label.text = @"English Header";
              }
              else{
                  label.text = @"中文 Header";
              }
      
              return label;
          }
      
          // 分段脚标题视图,UITableViewDelegate 协议方法
          - (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
      
              if (!section) {
                  label.text = @"English Footer";
              }
              else{
                  label.text = @"中文 Footer";
              }
      
              // 返回自定义的标题视图
              return label;
         }
      
    • 设置表格的表头和表尾视图

          // 设置表格的表头视图
          /*
              只有视图的高度设置起作用
          */
          myTableView.tableHeaderView = myHeaderView;
      
          // 设置表格的表尾视图
          /*
              只有视图的高度设置起作用
          */
          myTableView.tableFooterView = myFooterView;
      
    • 设置表格的背景

          // 设置表格的背景视图
          myTableView.backgroundView = myImageView;
      
          // 设置表格的背景颜色
          myTableView.backgroundColor = [UIColor blueColor];
      
    • 设置表格的分割线

          // 设置表格的分割线颜色
          /*
              设置为 clearColor 时即可隐藏(不显示)所有分割线
          */
          myTableView.separatorColor = [UIColor redColor];
      
          // 设置表格的分割线类型
          /*
              UITableViewCellSeparatorStyleNone,         // 没有分割线
              UITableViewCellSeparatorStyleSingleLine,   // 单线型,默认
      
              // 嵌刻线型,This separator style is only supported for grouped style
              UITableViewCellSeparatorStyleSingleLineEtched
          */
          myTableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
      
          // 设置表格的分割线边距
          /*
              上、左、下、右,只有左、右设置有效
              设置左边距时会使标题相应的右移
              左边距设置为 0 时,分割线不会紧靠左边框
          */
          myTableView.separatorInset = UIEdgeInsetsMake(0, 10, 0, 10);
      
          // 清除表格多余的分割线
          /*
              表格为 UITableViewStylePlain 类型时,若表格的内容没有占满屏幕时,没有设置内容的部分表格也会有分割线
              创建自定义的 view,将该 view 的背景颜色清空(默认为透明),并添加到表格的脚视图上
          */
          myTableView.tableFooterView = [[UIView alloc] init];
      
          // 设置表格分割线左边距为零
          [myTableView setSeparatorInset:UIEdgeInsetsZero];
          [myTableView setLayoutMargins:UIEdgeInsetsZero];
      
          - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{
              // UITableViewDelegate 协议方法
      
              [cell setSeparatorInset:UIEdgeInsetsZero];
              [cell setLayoutMargins:UIEdgeInsetsZero];
          }
      
          // 自定义表格分割线
          /*
              系统分割线的左边无法紧靠表格左边框,隐藏系统分割线,自定义视图,添加到 Cell 的下边实现
              同时可以清除表格在 UITableViewStylePlain 类型时的多余分割线
          */
      
          myTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
      
          if (cell == nil) {
      
              // 创建新的 cell
              cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:indentifier];
      
              // 添加自定义分割线视图
              CGRect frame = CGRectMake(0, cell.contentView.bounds.size.height, self.view.bounds.size.width, 1);
              UIView *mySeparatorView = [[UIView alloc] initWithFrame:frame];
              mySeparatorView.backgroundColor = [[UIColor lightGrayColor] colorWithAlphaComponent:0.5];
              [cell.contentView addSubview:mySeparatorView];
          }
      
    • 设置表格的行高

          // 属性设置
          /*
              设置全部行的高度,默认为 44
          */
          myTableView.rowHeight = 60;
      
          // 协议方法设置
          /*
              可单独设置每一行的高度,默认为 44
          */
          - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
      
              return 60;
          }
      
          // 设置估计行高
          /*
              设置全部行的高度
          */
          self.tableView.estimatedRowHeight = 80;
      
          // 协议方法设置估计行高
          /*
              可单独设置每一行的估计行高
          */
          - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
      
              return 80;
          }
      
          // 设置自动计算行高
          self.tableView.rowHeight = UITableViewAutomaticDimension;
      
    • 设置表格的编辑开关状态

          // 打开表格的编辑模式
          /*
              default is NO. setting is not animated
          */
          myTableView.editing = YES;
      
          // 翻转表格的编辑模式
          myTableView.editing = !myTableView.editing;
      
          // 翻转表格的编辑模式
          [myTableView setEditing:!myTableView.editing animated:YES];
      
    • 设置表格选择状态

          // 设置表格普通模式下是否允许单选
          /*
              default is YES. Controls whether rows can be selected when not in editing mode
          */
          myTableView.allowsSelection = YES;
      
          // 设置表格在编辑模式下是否允许单选
          /*
              default is NO. Controls whether rows can be selected when in editing mode
          */
          myTableView.allowsSelectionDuringEditing = YES;
      
          // 设置表格普通模式下是否允许多选
          /*
              default is NO. Controls whether multiple rows can be selected simultaneously
          */
          myTableView.allowsMultipleSelection = YES;
      
          // 设置表格在编辑模式下是否允许多选
          /*
              default is NO. Controls whether multiple rows can be selected simultaneously in editing mode
          */
          myTableView.allowsMultipleSelectionDuringEditing = YES;
      
          // 取消表格选择
          /*
              在表格选中协议方法中设置,表格点击变色后恢复原来颜色,设置后无法实现表格多选
          */
          [tableView deselectRowAtIndexPath:indexPath animated:YES];
      
    • 重载表格视图

          // 重载表格视图
          /*
              重走所有的表格视图方法,刷新所有的表格
          */
          [tableView reloadData];
      
          // 重载某一分段
          [tableView reloadSections:[NSIndexSet indexSetWithIndex:indexPath.section] 
                   withRowAnimation:UITableViewRowAnimationAutomatic];            
          // 重载某一个行
          [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] 
                           withRowAnimation:UITableViewRowAnimationAutomatic];
      
          // 删除一个 cell
          /*
              只刷新删除的 cell
          */
          [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] 
                           withRowAnimation:UITableViewRowAnimationAutomatic];
      
          // 插入一个 cell
          /*
              只刷新插入的 cell
          */
          [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] 
                           withRowAnimation:UITableViewRowAnimationAutomatic]; 
      
  • Swift

    • 设置分段的头标题和脚标题

          // 设置分段的头标题和脚标题的类型
          /*
              case Plain       // 简单模式,每个分段之间紧密连接,头脚标题悬浮显示,默认类型
              case Grouped     // 分组模式,每个分段之间分开,头脚标题跟随移动,头标题英文自动大写
          */
      
              // 头标题和脚标题悬浮显示,默认类型
              let myTableView:UITableView = UITableView()
      
              let myTableView:UITableView = UITableView(frame: frame)
      
              // 带显示类型的设置     
              let myTableView:UITableView = UITableView(frame: frame, style: .Grouped)
      
          // 设置分段的头标题高度,UITableViewDelegate 协议方法
          func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
      
              return  40
          }
      
          // 设置分段的脚标题高度,UITableViewDelegate 协议方法
          func tableView(tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
      
              return 30
          }
      
          // 设置分段的头标题内容,UITableViewDataSource 协议方法
          func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
      
              if 0 == section {
                  return "English Header"
              }
              else {
                  return "中文 Header"
              }
          }
      
          // 设置分段的脚标题内容,UITableViewDataSource 协议方法
          func tableView(tableView: UITableView, titleForFooterInSection section: Int) -> String? {
      
              if 0 == section {
                  return "English Footer"
              }
              else {
                  return "中文 Footer"
              }
          }
      
          // 分段头标题视图,UITableViewDelegate 协议方法,返回自定义的标题视图
          func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
      
              if 0 == section {
                  label.text = "English Header"
              }
              else {
                  label.text = "中文 Header"
              }
      
              return label
          }
      
          // 分段脚标题视图,UITableViewDelegate 协议方法,返回自定义的标题视图
          func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
      
              if 0 == section {
                  label.text = "English Footer"
              }
              else {
                  label.text = "中文 Footer"
              }
      
              return label
          }
      
    • 设置表格的表头和表尾视图

          // 设置表格的表头视图
          /*
              只有视图的高度设置起作用
          */
          myTableView.tableHeaderView = myHeaderView
      
          // 设置表格的表尾视图
          /*
              只有视图的高度设置起作用
          */
          myTableView.tableFooterView = myFooterView
      
    • 设置表格的背景

          // 设置表格的背景视图
          myTableView.backgroundView = myImageView
      
          // 设置表格的背景颜色
          myTableView.backgroundColor = UIColor.blueColor()
      
    • 设置表格的分割线

          // 设置表格的分割线颜色
          /*
              设置为 clearColor 时即可隐藏(不显示)所有分割线
          */
          myTableView.separatorColor = UIColor.redColor()
      
          // 设置表格分割线的类型
          /*
              case None                // 没有分割线
              case SingleLine          // 单线型,默认
              case SingleLineEtched    // 嵌刻线型,This separator style is only supported for grouped style
          */
          myTableView.separatorStyle = .SingleLine
      
          // 设置表格的分割线边距
          /*
              上、左、下、右,只有左、右设置有效
              设置左边距时会使标题相应的右移
              左边距设置为 0 时,分割线不会紧靠左边框
          */
          myTableView.separatorInset = UIEdgeInsetsMake(0, 10, 0, 10)
      
          // 清除表格多余的分割线
          /*
              表格为 Plain 类型时,若表格的内容没有占满屏幕时,没有设置内容的部分表格也会有分割线
              创建自定义的 view,将该 view 的背景颜色清空(默认为透明),并添加到表格的脚视图上
          */
          myTableView.tableFooterView = UIView()
      
          // 自定义表格分割线
          /*
              系统分割线的左边无法紧靠表格左边框,隐藏系统分割线,自定义视图,添加到 Cell 的下边实现
              同时可以清除表格在 Plain 类型时的多余分割线
          */
      
          myTableView.separatorStyle = .None
      
          if cell == nil {
      
              // 创建新的 cell
              cell = UITableViewCell(style: .Default, reuseIdentifier: indentifier)
      
              // 添加自定义分割线视图
              let frame:CGRect = CGRectMake(0, cell!.contentView.bounds.size.height, self.view.bounds.size.width, 1)
              let mySeparatorView:UIView = UIView(frame: frame)
              mySeparatorView.backgroundColor = UIColor.lightGrayColor().colorWithAlphaComponent(0.5)
              cell!.contentView.addSubview(mySeparatorView)
          }
      
    • 设置表格的行高

          // 属性设置
          /*
              设置全部行的高度,默认为 44
          */
          myTableView.rowHeight = 60
      
          // 协议方法设置
          /*
              可单独设置每一行的高度,默认为 44
          */
          func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
      
              return 60
          }
      
          // 设置估计行高
          /*
              设置全部行的高度
          */
          self.tableView.estimatedRowHeight = 80
      
          // 协议方法设置估计行高
          /*
              可单独设置每一行的估计行高
          */
          func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
      
              return 80
          }
      
          // 设置自动计算行高
          self.tableView.rowHeight = UITableViewAutomaticDimension
      
    • 设置表格的编辑开关状态

          // 打开表格的编辑模式
          myTableView.editing = true
      
          // 翻转表格的编辑模式,直接出现
          myTableView.editing = !myTableView.editing
      
          // 翻转表格的编辑模式,带动画效果
          myTableView.setEditing(!myTableView.editing, animated: true)
      
    • 设置表格选择状态

          // 设置表格普通模式下是否允许单选
          /*
              default is YES. Controls whether rows can be selected when not in editing mode
          */
          myTableView.allowsSelection = false
      
          // 设置表格在编辑模式下是否允许单选
          /*
              default is NO. Controls whether rows can be selected when in editing mode
          */
          myTableView.allowsSelectionDuringEditing = true
      
          // 设置表格普通模式下是否允许多选
          /*
              default is NO. Controls whether multiple rows can be selected simultaneously
          */
          myTableView.allowsMultipleSelection = true
      
          // 设置表格在编辑模式下是否允许多选
          /*
              default is NO. Controls whether multiple rows can be selected simultaneously in editing mode
          */
          myTableView.allowsMultipleSelectionDuringEditing = true
      
          // 取消表格选择
          /*
              在表格选中协议方法中设置,表格点击变色后恢复原来颜色,设置后无法实现表格多选
          */
          tableView.deselectRowAtIndexPath(indexPath, animated: true)
      
    • 重载表格视图

          // 重载表格视图
          /*
              重走所有的表格视图方法,刷新所有的表格
          */
          tableView.reloadData()
      
          // 重载某一分段
          tableView.reloadSections(NSIndexSet(index: indexPath.section), withRowAnimation: .Automatic)
      
          // 重载某一个行
          tableView.reloadRowsAtIndexPaths(Array(arrayLiteral: indexPath), withRowAnimation: .Automatic)
      
          // 删除一个 cell
          /*
              只刷新删除的 cell
          */
          tableView.deleteRowsAtIndexPaths(NSArray(object: indexPath) as! [NSIndexPath], 
                          withRowAnimation: .Automatic)
      
          // 插入一个 cell
          /*
              只刷新插入的 cell
          */
          tableView.insertRowsAtIndexPaths(NSArray(object: indexPath) as! [NSIndexPath], 
                          withRowAnimation: .Automatic)
      
TableViewCell 重复利用:
  • 分析:

虽然上面的代码实现了使用tableView展示数据,但是性能很差,为什么这么说,细心的人可能会有这样的疑问,UITableViewCell好像无止尽的在创建,少量的还能接受,如果有千万条数据,那么对于内存毫无疑问是一个打击,势必影响用户的体验,这里我们开始解释一个新的名词缓存池,他完美的解决了这个问题,有了缓存池之后系统只会创建屏幕范围内所包含的TableViewCell数量,当用户滑动屏幕时,被隐藏的Cell对象,系统会将该Cell扔到缓存池当中,等到下次被使用,而这个被隐藏的Cell也就是即将显示出来的新的Cell,Cell对象其实没发生变化的,变化的只是Cell内部的数据,有点抽象举个简单的例子,用五个袋子装苹果,目的:将苹果从地里搬运到地的顶头,我们要做的就是在地里把苹果塞满袋子,搬运到地的顶头,倒出苹果再拿着袋子去地里装苹果,这样我们就可以省掉好多人工成本,重复利用这个五个袋子。

  • 代码:
#import "ViewController.h"

// 使用tableView UITableViewDataSource 必须实现
@interface ViewController () <UITableViewDataSource>

@property (nonatomic, strong) UITableView *tableView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    [self.view addSubview:self.tableView];
}

/**
 *  通过懒加载方式创建tableView对象
 *
 *  @return tableView对象
 */
- (UITableView *)tableView
{
    if (!_tableView) {
        _tableView = [[UITableView alloc]init];
        CGSize SCREEN_SIZE = [UIScreen mainScreen].bounds.size;
        CGFloat tableViewX = 0;
        CGFloat tableViewY = 64;
        CGFloat tableViewWidth = SCREEN_SIZE.width;
        CGFloat tableViewHeight = SCREEN_SIZE.height-tableViewY;
        CGRect tableRect = CGRectMake(tableViewX, tableViewY, tableViewWidth, tableViewHeight);
        _tableView.frame = tableRect;
        _tableView.dataSource = self;
    }
    return _tableView;
}

// tableView 的代理,用来告诉tableView共有多少条数据Cell(这个代理是强制性的,必须实现)
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 10;
}

// tableView 的代理,用来告诉tableView每个cell都长什么样子(这个代理是强制性的,必须实现)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 缓存池里可能存在很多个tableViewCell对象,为了区分它们,我们必须创建一个唯一标识
    static NSString *identifier = @"cell";
    // 检查缓存池是否有对应标识的cell,如果有直接拿出来使用,如果没有创建并且扔到将新创建的cell扔到缓存池
    UITableViewCell *cell =[tableView dequeueReusableCellWithIdentifier:identifier];
    if (!cell) {
        cell = [[UITableViewCell alloc]init];
    }
    cell.textLabel.text = @"tableView 测试";
    return cell;
}
  • 验证:

为了验证我的说法,我们现在创建10条cell,然后打印cell对象,根据他们的内存地址判断他们是否被重复利用。

#import "ViewController.h"

// 使用tableView UITableViewDataSource 必须实现
@interface ViewController () <UITableViewDataSource,UITableViewDelegate>

@property (nonatomic, strong) UITableView *tableView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    [self.view addSubview:self.tableView];
}

/**
 *  通过懒加载方式创建tableView对象
 *
 *  @return tableView对象
 */
- (UITableView *)tableView
{
    if (!_tableView) {
        _tableView = [[UITableView alloc]init];
        CGSize SCREEN_SIZE = [UIScreen mainScreen].bounds.size;
        CGFloat tableViewX = 0;
        CGFloat tableViewY = 64;
        CGFloat tableViewWidth = SCREEN_SIZE.width;
        CGFloat tableViewHeight = SCREEN_SIZE.height-tableViewY;
        CGRect tableRect = CGRectMake(tableViewX, tableViewY, tableViewWidth, tableViewHeight);
        _tableView.frame = tableRect;
        _tableView.dataSource = self;
        _tableView.delegate = self;
    }
    return _tableView;
}

// tableView 的代理,用来告诉tableView共有多少条数据Cell(这个代理是强制性的,必须实现)
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 10;
}

// tableView 的代理,用来告诉tableView每个cell都长什么样子(这个代理是强制性的,必须实现)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 缓存池里可能存在很多个tableViewCell对象,为了区分它们,我们必须创建一个唯一标识
    static NSString *identifier = @"cell";
    // 检查缓存池是否有对应标识的cell,如果有直接拿出来使用,如果没有创建并且扔到将新创建的cell扔到缓存池
    UITableViewCell *cell =[tableView dequeueReusableCellWithIdentifier:identifier];
    if (!cell) {
        cell = [[UITableViewCell alloc]init];
    }
    cell.textLabel.text = @"tableView 测试";
    NSLog(@"Cell --> %@",cell);
    return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 200;
}

日志Log:

**2016-07-11 11:20:32.265 UITableViewDemo[1862:66650] Cell --> <UITableViewCell: 0x7fb623c3e6f0; frame = (0 0; 320 44); text = 'tableView ****测试****'; layer = <CALayer: 0x7fb623c3eb50>>**
**2016-07-11 11:20:32.267 UITableViewDemo[1862:66650] Cell --> <UITableViewCell: 0x7fb623f28170; frame = (0 0; 320 44); text = 'tableView ****测试****'; layer = <CALayer: 0x7fb623f2c740>>**
**2016-07-11 11:20:32.268 UITableViewDemo[1862:66650] Cell --> <UITableViewCell: 0x7fb623d5ca10; frame = (0 0; 320 44); text = 'tableView ****测试****'; layer = <CALayer: 0x7fb623d5a9c0>>**
**2016-07-11 11:20:32.268 UITableViewDemo[1862:66650] Cell --> <UITableViewCell: 0x7fb623ea4010; frame = (0 0; 320 44); text = 'tableView ****测试****'; layer = <CALayer: 0x7fb623ea3070>>**
**2016-07-11 11:20:37.120 UITableViewDemo[1862:66650] Cell --> <UITableViewCell: 0x7fb623c27ea0; frame = (0 0; 320 44); text = 'tableView ****测试****'; layer = <CALayer: 0x7fb623c411f0>>**
**2016-07-11 11:20:38.301 UITableViewDemo[1862:66650] Cell --> <UITableViewCell: 0x7fb623c3e6f0; frame = (0 0; 320 44); text = 'tableView ****测试****'; layer = <CALayer: 0x7fb623c72740>>**
**2016-07-11 11:20:39.997 UITableViewDemo[1862:66650] Cell --> <UITableViewCell: 0x7fb623c1bbd0; frame = (0 0; 320 44); text = 'tableView ****测试****'; layer = <CALayer: 0x7fb623c43160>>**
**2016-07-11 11:20:40.377 UITableViewDemo[1862:66650] Cell --> <UITableViewCell: 0x7fb623c1eee0; frame = (0 0; 320 44); text = 'tableView ****测试****'; layer = <CALayer: 0x7fb623c4e710>>**
**2016-07-11 11:20:42.153 UITableViewDemo[1862:66650] Cell --> <UITableViewCell: 0x7fb623c1f650; frame = (0 0; 320 44); text = 'tableView ****测试****'; layer = <CALayer: 0x7fb623c293f0>>**
**2016-07-11 11:20:42.562 UITableViewDemo[1862:66650] Cell --> <UITableViewCell: 0x7fb623c27ea0; frame = (0 0; 320 44); text = 'tableView ****测试****'; layer = <CALayer: 0x7fb623c3c1e0>>**
**2016-07-11 11:21:05.947 UITableViewDemo[1862:66650] Cell --> <UITableViewCell: 0x7fb623c2a660; frame = (0 0; 320 44); text = 'tableView ****测试****'; layer = <CALayer: 0x7fb623c265f0>>**
**2016-07-11 11:21:06.390 UITableViewDemo[1862:66650] Cell --> <UITableViewCell: 0x7fb623d5ca10; frame = (0 0; 320 44); text = 'tableView ****测试****'; layer = <CALayer: 0x7fb623d59b10>>**
**2016-07-11 11:21:07.704 UITableViewDemo[1862:66650] Cell --> <UITableViewCell: 0x7fb623d17df0; frame = (0 0; 320 44); text = 'tableView ****测试****'; layer = <CALayer: 0x7fb623d5d460>>**
**2016-07-11 11:21:08.163 UITableViewDemo[1862:66650] Cell --> <UITableViewCell: 0x7fb623c1eee0; frame = (0 0; 320 44); text = 'tableView ****测试****'; layer = <CALayer: 0x7fb623c28d40>>**
**2016-07-11 11:21:10.269 UITableViewDemo[1862:66650] Cell --> <UITableViewCell: 0x7fb623c20cc0; frame = (0 0; 320 44); text = 'tableView ****测试****'; layer = <CALayer: 0x7fb623c73040>>**
**2016-07-11 11:21:10.753 UITableViewDemo[1862:66650] Cell --> <UITableViewCell: 0x7fb623c27ea0; frame = (0 0; 320 44); text = 'tableView ****测试****'; layer = <CALayer: 0x7fb623c3dde0>>**

图片 2

Paste_Image.png

  • 结论:通过日志我们可以发现有好多Cell内存地址一样,那只能证明我的说法是正确的,缓存池确实让tableViewCell达到了重复利用的。

3、Cell 的创建(系统类型 Cell)

  • 使用 dequeueReuseableCellWithIdentifier: 可不注册,但是必须对获取回来的 cell 进行判断是否为空,若空则手动创建新的 cell;
  • 使用 dequeueReuseableCellWithIdentifier: forIndexPath: 必须注册,但返回的 cell 可省略空值判断的步骤。

  • tableViewCell 的复用机制:

    • 1、当一个 cell 滑出屏幕的时候,会被放到复用队列里(系统自动操作)。
    • 2、当一个 cell 即将出现的时候,我们需要先从复用队列里查找,找到就直接用,找不到就创建。
  • 系统 Cell 的创建方式:

    • 代码创建 cell。
    • 注册 cell。
    • 从 storyboard 加载 cell。
UITableViewCell的多种创建模式:

UITableViewCell一般可以使用系统自带的(UITableViewCell),也可以继承UITableViewCell类创建自定义的Cell,自定义的Cell的创建一般有两种方式,一种是通过纯代码创建,一种是使用xib方式创建,这些方式没有好与坏之分,只能根据实际需求选择最适合自己的方式就行,下面我们快速的通过这几种方式创建tableViewCell。

  • .系统默认的TableViewCell:
#import "ViewController.h"

// 使用tableView UITableViewDataSource 必须实现
@interface ViewController () <UITableViewDataSource,UITableViewDelegate>

@property (nonatomic, strong) UITableView *tableView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    [self.view addSubview:self.tableView];
}

/**
 *  通过懒加载方式创建tableView对象
 *
 *  @return tableView对象
 */
- (UITableView *)tableView
{
    if (!_tableView) {
        _tableView = [[UITableView alloc]init];
        CGSize SCREEN_SIZE = [UIScreen mainScreen].bounds.size;
        CGFloat tableViewX = 0;
        CGFloat tableViewY = 64;
        CGFloat tableViewWidth = SCREEN_SIZE.width;
        CGFloat tableViewHeight = SCREEN_SIZE.height-tableViewY;
        CGRect tableRect = CGRectMake(tableViewX, tableViewY, tableViewWidth, tableViewHeight);
        _tableView.frame = tableRect;
        _tableView.dataSource = self;
        _tableView.delegate = self;
    }
    return _tableView;
}

// tableView 的代理,用来告诉tableView共有多少条数据Cell(这个代理是强制性的,必须实现)
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 10;
}

// tableView 的代理,用来告诉tableView每个cell都长什么样子(这个代理是强制性的,必须实现)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 缓存池里可能存在很多个tableViewCell对象,为了区分它们,我们必须创建一个唯一标识
    static NSString *identifier = @"cell";
    // 检查缓存池是否有对应标识的cell,如果有直接拿出来使用,如果没有创建并且扔到将新创建的cell扔到缓存池
    UITableViewCell *cell =[tableView dequeueReusableCellWithIdentifier:identifier];
    if (!cell) {
        // 系统默认提供的cell的样式有4种
        // UITableViewCellStyleDefault,     // Simple cell with text label and optional image view (behavior of UITableViewCell in iPhoneOS 2.x)
        // UITableViewCellStyleValue1,  // 设置cell的详细内容显示在主文字的后面
        // UITableViewCellStyleValue2,  // 设置cell的详细内容显示在主文字的前面(会覆盖前面imageView)
        // UITableViewCellStyleSubtitle     // 设置cell的详细内容显示在主文字的下方
        cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
    }
    // 设置主文字
    cell.textLabel.text = @"tableView 测试";

    // 设置图片
    cell.imageView.image = [UIImage imageNamed:@"icon"];

    // 设置cell的详细内容 并且cell的样式不能填写 (UITableViewCellStyleDefault),如果填写,则cell的详细内容不显示
    cell.detailTextLabel.text = @"tableViewCell的详细内容";

    // 设置cell后端显示的图标(使用系统提供的图标)
    // UITableViewCellAccessoryNone,     什么都不显示
    // UITableViewCellAccessoryDisclosureIndicator,                              显示一个指向右端的箭头
    // UITableViewCellAccessoryDetailDisclosureButton __TVOS_PROHIBITED,         显示一个叹号
    // UITableViewCellAccessoryCheckmark,                                        显示一个选中的对号
    // UITableViewCellAccessoryDetailButton                                      显示一个叹号
    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;

    // 自定义cell末尾显示的UIView对象
    cell.accessoryView = [[UISwitch alloc]init];

    return cell;
}
  • 自定义TableViewCell:

3.1 创建 Cell

  • 可以设置创建的 Cell 的类型。

  • Objective-C

        // 设置每一行显示的内容
        - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
            // 创建标识词,标识词随意设置,但不能和其它 tableView 的相同
            static NSString *resumeID = @"testIdentifier";
    
            // 根据标识词先从复用队列里查找
            UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:resumeID];
    
            // 复用队列中没有时再创建
            if (cell == nil) {
    
               // 创建新的 cell,默认为主标题模式
               cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault reuseIdentifier:resumeID];
            }
    
            // 设置每一行显示的文字内容,覆盖数据
            cell.textLabel.text = [[myDataArray objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
            cell.imageView.image = [UIImage imageNamed:@"HQ_0003"];
    
            return cell;
        }
    
  • Swift

        // 设置每一行显示的内容
        func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    
            // 创建标识词,标识词随意设置,但不能和其它 tableView 的相同
            let resumeID = "testIdentifier"
    
            // 根据标识词先从复用队列里查找
            var cell = tableView.dequeueReusableCellWithIdentifier(resumeID)
    
            // 复用队列中没有时再创建
            if cell == nil {
    
                // 创建新的 cell,默认为主标题模式
                cell = UITableViewCell(style: .Default, reuseIdentifier: resumeID)
            }
    
            // 设置每一行显示的文字内容,覆盖数据
            cell!.textLabel?.text = myDataArray[indexPath.section][indexPath.row]
            cell!.imageView?.image = UIImage(named: "HQ_0003")
    
            return cell!
        }
    
效果:

在自定义的Cell中添加两个图片和一个TableView视图。

// 自定义Cell部分:
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>

@interface TempTableView  : NSObject <UITableViewDataSource,UITableViewDelegate>

@end

@interface CustomTableViewCell : UITableViewCell

@end

#import "CustomTableViewCell.h"

@interface CustomTableViewCell()

@property (nonatomic, strong) UIImageView *image1;
@property (nonatomic, strong) UIImageView *image2;
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) TempTableView *tempTableVew;

@end

@implementation TempTableView

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 10;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *identifier = @"cells";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
    if (!cell) {
        cell = [[UITableViewCell alloc]init];
    }

    cell.textLabel.text = @"测试数据";
    return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 20;
}

@end

@implementation CustomTableViewCell

- (instancetype)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame]) {

        [self addSubViews];
    }
    return self;
}

- (UIImageView *)image1
{
    if (!_image1) {
        _image1 = [[UIImageView alloc]init];
        _image1.image = [UIImage imageNamed:@"icon1"];
    }
    return _image1;
}

- (UIImageView *)image2
{
    if (!_image2) {
        _image2 = [[UIImageView alloc]init];
        _image2.image = [UIImage imageNamed:@"icon"];
    }
    return _image2;
}

- (UITableView *)tableView
{
    if (!_tableView) {
        _tableView = [[UITableView alloc]init];
        _tableView.dataSource = self.tempTableVew;
        _tableView.delegate = self.tempTableVew;

    }
    return _tableView;
}

- (TempTableView *)tempTableVew
{
    if (!_tempTableVew) {
        _tempTableVew = [[TempTableView alloc]init];
    }
    return _tempTableVew;
}

- (void)addSubViews
{
    [self addSubview:self.image1];
    [self addSubview:self.image2];
    [self addSubview:self.tableView];
}

- (void)layoutSubviews
{
    [super layoutSubviews];

    CGRect rect = self.frame;
    rect.size.width = self.frame.size.width / 2 ;
    rect.origin.y = 0;
    rect.origin.x = rect.size.width;
    self.tableView.frame = rect;

    CGRect rectI1 = self.frame;
    rectI1.origin.y = 0;
    rectI1.size.width = self.frame.size.width / 4 ;
    self.image1.frame = rectI1;

    CGRect rectI2 = self.frame;
     rectI2.origin.y = 0;
    rectI2.size.width = self.frame.size.width / 4 ;
    rectI2.origin.x = rectI2.size.width;
    self.image2.frame = rectI2;
}
@end

// 展示部分
#import "ViewController.h"
#import "CustomTableViewCell.h"

// 使用tableView UITableViewDataSource 必须实现
@interface ViewController () <UITableViewDataSource,UITableViewDelegate>

@property (nonatomic, strong) UITableView *tableView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    [self.view addSubview:self.tableView];
}

/**
 *  通过懒加载方式创建tableView对象
 *
 *  @return tableView对象
 */
- (UITableView *)tableView
{
    if (!_tableView) {
        _tableView = [[UITableView alloc]init];
        CGSize SCREEN_SIZE = [UIScreen mainScreen].bounds.size;
        CGFloat tableViewX = 0;
        CGFloat tableViewY = 64;
        CGFloat tableViewWidth = SCREEN_SIZE.width;
        CGFloat tableViewHeight = SCREEN_SIZE.height-tableViewY;
        CGRect tableRect = CGRectMake(tableViewX, tableViewY, tableViewWidth, tableViewHeight);
        _tableView.frame = tableRect;
        _tableView.dataSource = self;
        _tableView.delegate = self;
    }
    return _tableView;
}

// tableView 的代理,用来告诉tableView共有多少条数据Cell(这个代理是强制性的,必须实现)
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 10;
}

// tableView 的代理,用来告诉tableView每个cell都长什么样子(这个代理是强制性的,必须实现)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 缓存池里可能存在很多个tableViewCell对象,为了区分它们,我们必须创建一个唯一标识
    static NSString *identifier = @"cell";
    // 检查缓存池是否有对应标识的cell,如果有直接拿出来使用,如果没有创建并且扔到将新创建的cell扔到缓存池
    CustomTableViewCell *cell =[tableView dequeueReusableCellWithIdentifier:identifier];
    if (!cell) {
        cell = [[CustomTableViewCell alloc]init];
    }
    return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 100;
}

@end

效果图:

图片 3

QQ20160711-2.png

  • 通过xib方式实现TableViewCell:
    xib 方式的使用步骤:
  1. 创建一个继承UITabelViewCell的类文件。
  2. 在创建UITabelViewCell类文件时,系统未能帮我们创建绑定的xib文件,那么我们必须手动创建,xib文件名称保持和UITabelViewCell类文件的名称一致,带创建好xib之后,删除xib中的UIView对象,将UITableViewCell控件拖入到xib中。
  3. 配置xib文件
![](https://upload-images.jianshu.io/upload_images/1331851-ef06f820931eb3ef.png)

QQ20160711-0.png

首先选中xib中UITableViewCell控件,看上图红色区域,Class选项选择刚创建的UITabelViewCell类文件,下面的Restoration ID 就是那个缓存用的唯一标识。

#import <UIKit/UIKit.h>

@interface XibTableViewCell : UITableViewCell

@property (nonatomic, copy) NSString *title;

@end

#import "XibTableViewCell.h"

@interface XibTableViewCell()

@property (weak, nonatomic) IBOutlet UILabel *label;

@end

@implementation XibTableViewCell

- (void)setTitle:(NSString *)title
{
    _title = title;
    self.label.text = _title;
}

@end

#import "ViewController.h"
#import "CustomTableViewCell.h"
#import "XibTableViewCell.h"

// 使用tableView UITableViewDataSource 必须实现
@interface ViewController () <UITableViewDataSource,UITableViewDelegate>

@property (nonatomic, strong) UITableView *tableView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    [self.view addSubview:self.tableView];
}

/**
 *  通过懒加载方式创建tableView对象
 *
 *  @return tableView对象
 */
- (UITableView *)tableView
{
    if (!_tableView) {
        _tableView = [[UITableView alloc]init];
        CGSize SCREEN_SIZE = [UIScreen mainScreen].bounds.size;
        CGFloat tableViewX = 0;
        CGFloat tableViewY = 64;
        CGFloat tableViewWidth = SCREEN_SIZE.width;
        CGFloat tableViewHeight = SCREEN_SIZE.height-tableViewY;
        CGRect tableRect = CGRectMake(tableViewX, tableViewY, tableViewWidth, tableViewHeight);
        _tableView.frame = tableRect;
        _tableView.dataSource = self;
        _tableView.delegate = self;
    }
    return _tableView;
}

// tableView 的代理,用来告诉tableView共有多少条数据Cell(这个代理是强制性的,必须实现)
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 10;
}

// tableView 的代理,用来告诉tableView每个cell都长什么样子(这个代理是强制性的,必须实现)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    XibTableViewCell *cell = [[NSBundle mainBundle]loadNibNamed:@"XibTableViewCell" owner:nil options:nil].firstObject;
    cell.title = [NSString stringWithFormat:@"%@",@(indexPath.row)];
    return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 100;
}
@end

效果图:

图片 4

效果图

总结:

以上就是三种创建UITableViewCell的方式,自定义适合强自定义的界面设计,xib适合使用使用系统提供的控件对象界面设计,UITableViewCell适合简单的界面设计。

3.2 注册 Cell

  • 在 tableView 创建时,从 iOS7 开始多了一种创建 cell 的方式(注册),让 tableView 注册一种 cell,需要设置复用标志。

  • 创建的 Cell 为 UITableViewCellStyleDefault 默认类型,无法修改。

  • Objective-C

        // 定义重用标识,定义为全局变量
        NSString *resumeID = @"testIdentifier";
    
        // 注册 cell
        - (void)viewDidLoad {
            [super viewDidLoad];
    
            // 注册某个标识对应的 cell 类型
            [myTableView registerClass:[UITableViewCell class] forCellReuseIdentifier:resumeID];
        }
    
        // 设置每一行显示的内容
        - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
            // 根据标识词先从复用队列里查找,复用队列中没有时根据注册的 cell 自动创建
            UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:resumeID forIndexPath:indexPath]; 
    
            // 设置每一行显示的文字内容,覆盖数据
            cell.textLabel.text = [[myDataArray objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
            cell.imageView.image = [UIImage imageNamed:@"HQ_0003"];
    
            return cell;
        }
    
  • Swift

        // 定义重用标识,定义为全局变量
        let resumeID = "testIdentifier"
    
        // 注册 cell
        override func viewDidLoad() {
            super.viewDidLoad()
    
            // 注册某个标识对应的 cell 类型
            myTableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: resumeID)
        }
    
        // 设置每一行显示的内容
        func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    
            // 根据标识词先从复用队列里查找,复用队列中没有时根据注册的 cell 自动创建
            var cell = tableView.dequeueReusableCellWithIdentifier(resumeID, forIndexPath: indexPath)
    
            // 设置每一行显示的文字内容,覆盖数据
            cell!.textLabel?.text = myDataArray[indexPath.section][indexPath.row]
            cell!.imageView?.image = UIImage(named: "HQ_0003")
    
            return cell!
        }
    

3.3 StoryBoard 加载 Cell

  • 在 storyboard 中设置 UITableView 的 Dynamic Prototypes Cell。

    图片 5

  • 设置 cell 的重用标识。

    图片 6

  • 在代码中利用重用标识获取 cell。

    • Objective-C

          // 设置每一行显示的内容
          - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
      
              // 创建标识词,标识词随意设置,但不能和其它 tableView 的相同
              static NSString *resumeID = @"cell";
      
              // 根据标志词从先复用队列里查找,复用队列中没有时根据 storyboard 自动创建
              UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:resumeID forIndexPath:indexPath]; 
      
              // 设置每一行显示的文字内容,覆盖数据
              cell.textLabel.text = [[myDataArray objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
              cell.imageView.image = [UIImage imageNamed:@"HQ_0003"];
      
              return cell;
          }
      
    • Swift

          // 设置每一行显示的内容
          func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
      
              // 创建标识词,标识词随意设置,但不能和其它 tableView 的相同
              let resumeID = "cell"
      
              // 根据标志词从先复用队列里查找,复用队列中没有时根据 storyboard 自动创建
              var cell = tableView.dequeueReusableCellWithIdentifier(resumeID, forIndexPath: indexPath)
      
              // 设置每一行显示的文字内容,覆盖数据
              cell!.textLabel?.text = myDataArray[indexPath.section][indexPath.row]
              cell!.imageView?.image = UIImage(named: "HQ_0003")
      
              return cell!
          }
      

4、Cell 的设置

  • UITableView 的每一行都是一个 UITableViewCell,通过 dataSource的tableView:cellForRowAtIndexPath: 方法来初始化每一行。

  • UITableViewCell 内部有个默认的子视图 contentView,contentView 是 UITableViewCell 所显示内容的父视图,可显示一些辅助指示视图。辅助指示视图的作用是显示一个表示动作的图标,可以通过设置 UITableViewCell 的 accessoryType 来显示,默认是 UITableViewCellAccessoryNone (不显示辅助指示视图)。

  • contentView 下默认有 3 个子视图

    • 其中 2 个是 UILabel (通过 UITableViewCell 的 textLabel 和 detailTextLabel 属性访问)。
    • 第 3 个是 UIImageView (通过 UITableViewCell 的 imageView 属性访问)。
  • UITableViewCell 还有一个 UITableViewCellStyle 属性,用于决定使用 contentView 的哪些子视图,以及这些子视图在 contentView 中的位置。

    图片 7

  • UITableViewCell 结构

    图片 8

  • Objective-C

    • 设置 Cell 的类型

          /*
              UITableViewCellStyleDefault,  // 可选图片 + 主标题模式,默认
              UITableViewCellStyleValue1,   // 可选图片 + 左右主副标题模式,两端对齐
              UITableViewCellStyleValue2,   // 左右主副标题模式,中间对齐
              UITableViewCellStyleSubtitle  // 可选图片 + 上下主副标题模式
          */
      
          // 主标题模式,默认类型
          cell = [[UITableViewCell alloc] init];
      
          // 设置类型
          cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"testIdentifier"];
      
    • 设置 Cell 的显示内容

          // 主标题模式
      
              // 设置主标题内容
              cell.textLabel.text = [[myDataArray objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
      
              // 设置图片内容,图片在 Cell 的左端,图片大小自动压缩
              cell.imageView.image = [UIImage imageNamed:@"HQ_0003"];
      
          // 主副标题模式
      
              // 设置主标题内容
              cell.textLabel.text = [[myDataArray objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
      
              // 设置副标题内容
              cell.detailTextLabel.text = [NSString stringWithFormat:@"第 %li 行", indexPath.row];
      
              // 设置图片内容,图片在 Cell 的左端,图片大小自动压缩
              cell.imageView.image = [UIImage imageNamed:@"HQ_0003"];
      
    • 往 cell 上添加自定义 view

      • 不是直接添加在 cell 上,cell 给我们提供了一个专门用来添加子 view 的东西,当 cell 被复用的时候,不允许创建对象,如果想给系统的 cell 上添加一些子 view,需要在创建 cell 的时候添加,然后在复用的时候修改子 view 显示的内容。
          // 添加 cell 自定义 view 视图
          UILabel *myCellView = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 300, 44)];
          myCellView.tag = 100;
      
          // 在创建新的 cell 后添加
          [cell.contentView addSubview:myCellView];
      
          // 设置 cell 自定义 view 显示内容,在 cell 复用的时候设置
      
          UILabel *myCellView = (id)[self.view viewWithTag:100];
          myCellView.text = [NSString stringWithFormat:@"自定义 Cell View %@", 
                           [[myDataArray objectAtIndex:indexPath.section] 
                                         objectAtIndex:indexPath.row]];
      
    • 设置 Cell 的背景视图

          // Cell 的背景视图设置
          /*
              设置自定义视图为 Cell 背景视图
              图片大小自动压缩填充
          */
          cell.backgroundView = myBackgroundView;
      
            // Cell 选中时的背景视图设置
            cell.selectedBackgroundView = myBackgroundView;

-   设置 Cell 的颜色

            // Cell 背景颜色的设置
            cell.backgroundColor = [UIColor yellowColor];

            // 设置 cell 被点击时的颜色
            /*
                UITableViewCellSelectionStyleNone,     // 无色,表格点击时无颜色变化
                UITableViewCellSelectionStyleBlue,     // 灰色
                UITableViewCellSelectionStyleGray,     // 灰色
                UITableViewCellSelectionStyleDefault   // 灰色,默认
            */
            cell.selectionStyle = UITableViewCellSelectionStyleDefault;

            // 取消表格选择变色
            /*
                在表格选中协议方法中设置,表格点击变色后恢复原来颜色,设置后无法实现表格多选
            */
            [tableView deselectRowAtIndexPath:indexPath animated:YES];

-   设置 Cell 的附属控件

            // Cell 附属控件类型的设置
            /*
                如果附属控件里有 button ,这个 button 会独立出来

                UITableViewCellAccessoryNone,                    // 无附属控件,默认
                UITableViewCellAccessoryDisclosureIndicator,     // 箭头,不能点击
                UITableViewCellAccessoryDetailDisclosureButton,  // 详情按钮和箭头,可以点击
                UITableViewCellAccessoryCheckmark,               // 对号,不能点击
                UITableViewCellAccessoryDetailButton             // 详情按钮,可以点击
            */
            cell.accessoryType = UITableViewCellAccessoryCheckmark;

            // Cell 附属控件视图的设置
            /*
                设置自定义视图为 Cell 的附属控件,需设置 view 的大小
            */
            cell.accessoryView = myAccessoryView;

-   获取 cell

            // 获取指定行的 cell
            UITableViewCell *cell = [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:3 inSection:0]];

            // 获取所有被选中的行
            NSArray *indexPaths = [tableView indexPathsForSelectedRows];
  • Swift

    • 设置 Cell 的类型

          /*
              case Default   // 可选图片 + 主标题模式
              case Value1    // 可选图片 + 左右主副标题模式,两端对齐
              case Value2    // 左右主副标题模式,中间对齐
              case Subtitle  // 可选图片 + 上下主副标题模式
          */
      
          // 主标题模式,默认类型
          cell = UITableViewCell()
      
          // 设置类型
          cell = UITableViewCell(style: .Subtitle, reuseIdentifier: "testIdentifier")
      
    • 设置 Cell 的显示内容

          // 主标题模式
      
              // 设置主标题内容
              cell!.textLabel?.text = myDataArray[indexPath.section][indexPath.row]
      
              // 设置图片内容,图片在 Cell 的左端,图片大小自动压缩
              cell!.imageView?.image = UIImage(named: "HQ_0003")
      
          // 主副标题模式
      
              // 设置主标题内容
              cell!.textLabel?.text = myDataArray[indexPath.section][indexPath.row]
      
              // 设置副标题内容
              cell!.detailTextLabel?.text = "第 (indexPath.row) 行"
      
              // 设置图片内容,图片在 Cell 的左端,图片大小自动压缩
              cell!.imageView?.image = UIImage(named: "HQ_0003")
      
    • 往 cell 上添加自定义 view

      • 不是直接添加在 cell 上,cell 给我们提供了一个专门用来添加子 view 的东西,当 cell 被复用的时候,不允许创建对象,如果想给系统的 cell 上添加一些子 view,需要在创建 cell 的时候添加,然后在复用的时候修改子 view 显示的内容。
          // 添加 cell 自定义 view 视图
          let myCellView:UILabel = UILabel(frame: CGRectMake(0, 0, 300, 44))
          myCellView.tag = 100
      
          // 在创建新的 cell 后添加
          cell!.contentView.addSubview(myCellView)
      
          // 设置 cell 自定义 view 显示内容,在 cell 复用的时候设置
      
          if (self.view.viewWithTag(100) != nil) {
      
              let myCellView = self.view.viewWithTag(100) as! UILabel
              myCellView.text = String("自定义 Cell View (myDataArray[indexPath.section][indexPath.row])")
          }
      
    • 设置 Cell 的背景视图

          // Cell 的背景视图设置
          /*
              设置自定义视图为 Cell 背景视图
              图片大小自动压缩填充
          */
          cell!.backgroundView = myBackgroundView
      
            // Cell 选中时的背景视图设置
            cell!.selectedBackgroundView = myBackgroundView

-   设置 Cell 的颜色

            // Cell 背景颜色的设置
            cell!.backgroundColor = UIColor.yellowColor()

            // 设置 cell 被点击时的颜色
            /*
                case None     // 无色,表格点击时无颜色变化
                case Blue     // 灰色
                case Gray     // 灰色
                case Default  // 灰色,默认
            */
            cell!.selectionStyle = UITableViewCellSelectionStyle.Default

            // 取消表格选择变色
            /*
                在表格选中协议方法中设置,表格点击变色后恢复原来颜色,设置后无法实现表格多选
            */
            tableView.deselectRowAtIndexPath(indexPath, animated: true)

-   设置 Cell 的附属控件

            // Cell 附属控件类型的设置
            /*
                如果附属控件里有 button ,这个 button 会独立出来

                case None                      // 无附属控件,默认
                case DisclosureIndicator       // 箭头,不能点击
                case DetailDisclosureButton    // 详情按钮和箭头,可以点击
                case Checkmark                 // 对号,不能点击
                case DetailButton              // 详情按钮,可以点击
            */
            cell!.accessoryType = UITableViewCellAccessoryType.DetailButton

            // Cell 附属控件视图的设置
            /*
                设置自定义视图为 Cell 的附属控件,需设置 view 的大小
            */
            cell!.accessoryView = myAccessoryView

-   获取 cell

            // 获取指定行的 cell
            let cell:UITableViewCell = tableView.cellForRowAtIndexPath(NSIndexPath(forItem: 3, inSection: 0))!

            // 获取所有被选中的行
            let indexPaths:[NSIndexPath] = tableView.indexPathsForVisibleRows!

5、自定义数据模型的创建与引用

  • Objective-C

    • BookModel.h

          @interface BookModel : NSObject
      
          // 根据需要使用的数据创建数据模型属性变量
      
          @property(nonatomic, copy)NSString *title;
          @property(nonatomic, copy)NSString *detail;
          @property(nonatomic, copy)NSString *icon;
          @property(nonatomic, copy)NSString *price;
      
          + (instancetype)bookModelWithDict:(NSDictionary *)dict;
      
          @end
      
    • BookModel.m

          + (instancetype)bookModelWithDict:(NSDictionary *)dict {
      
              BookModel *model = [[self alloc] init];
      
              // KVC - Key Value Coding
              [model setValuesForKeysWithDictionary:dict];
      
              return model;
          }
      
    • ViewController.m

          // 向数据源中添加数据
      
              // 定义数据源
              @property(nonatomic, retain)NSArray *myDataArray;
      
              // 懒加载
              - (NSArray *)myDataArray {
                  if (_myDataArray == nil) {
      
                      // 加载 plist 中的字典数组
                      NSString *filePath = [[NSBundle mainBundle] pathForResource:@"bookData" ofType:@"plist"];
                      NSArray *bookDataArray = [NSArray arrayWithContentsOfFile:filePath];
      
                      // 字典数组 -> 模型数组
                      NSMutableArray *dataArrayM = [NSMutableArray arrayWithCapacity:bookDataArray.count];
                      for (NSDictionary *bookInfoDic in bookDataArray) {
                          BookModel *bookModel = [BookModel bookModelWithDict:bookInfoDic];
                          [dataArrayM addObject:bookModel];
                      }
      
                      // 将从文件中取出的数据添加到数据源数组中
                      _myDataArray = [dataArrayM copy];
                  }
                  return _myDataArray;
              }
      
          // 从数据源中取出数据
      
              // UITableViewDataSource 协议方法
              - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
      
                  // 从数据源数组中取出数据
                  BookModel *bookModel = [self.myDataArray objectAtIndex:indexPath.row];
      
                  // 配置自定义 Cell 子视图上显示的内容
                  cell.book = bookModel;
              }
      
  • Swift

    • BookModel.swift

          class BookModel: NSObject {
      
              // 根据需要使用的数据创建数据模型属性变量
      
              var title:String?
              var detail:String?
              var icon:String?
              var price:String?
      
              class func bookModelWithDict(dict:[String : AnyObject]) -> AnyObject {
      
                  let model = BookModel()
      
                  // KVC - Key Value Coding
                  model.setValuesForKeysWithDictionary(dict)
      
                  return model
              }
          }
      
    • ViewController.swift

          // 向数据源中添加数据
      
              // 定义数据源,懒加载
              lazy var myDataArray:[BookModel] = {
      
                  // 加载 plist 中的字典数组
                  let filePath:String = NSBundle.mainBundle().pathForResource("bookData", ofType: "plist")!
                  let bookDataArray:NSArray = NSArray(contentsOfFile: filePath)!
      
                  // 字典数组 -> 模型数组
                  var dataArrayM:NSMutableArray = NSMutableArray(capacity: bookDataArray.count)
                  for bookInfoDic in bookDataArray {
                      let bookModel:BookModel = BookModel.bookModelWithDict(bookInfoDic as! NSDictionary)
                      dataArrayM.addObject(bookModel)
                  }
      
                  // 将从文件中取出的数据添加到数据源数组中
                  return dataArrayM.copy() as! [BookModel]
              }()
      
          // 从数据源中取出数据
      
              // UITableViewDataSource 协议方法
              func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
      
                  // 从数据源数组中取出数据
                  let bookModel:BookModel = self.myDataArray[indexPath.row]
      
                  // 配置自定义 Cell 子视图上显示的内容
                  cell!.configWithModel(bookModel)
              }
      

6、自定义等高 Cell

6.1 StoryBoard 自定义 cell

  • 创建一个继承自 UITableViewCell 的子类,比如 XMGDealCell。

    图片 9

  • 在 storyboard 中

    • 往 cell 里面增加需要用到的子控件。

      图片 10

    • 设置 cell 的重用标识 。

      图片 11

    • 设置 cell 的 class 为 XMGDealCell。

      图片 12

  • 在 XMGDealCell 中

    • 将 storyboard 中的子控件连线到类扩展中。
    • 需要提供一个模型属性,重写模型的 set 方法,在这个方法中设置模型数据到子控件上。
  • 在控制器中
    • 利用重用标识找到 cell。
    • 给 cell 传递模型数据。
  • Objective-C

    • XMGDeal.h

          @interface XMGDeal : NSObject
      
          @property (strong, nonatomic) NSString *buyCount;
          @property (strong, nonatomic) NSString *price;
          @property (strong, nonatomic) NSString *title;
          @property (strong, nonatomic) NSString *icon;
      
          + (instancetype)dealWithDict:(NSDictionary *)dict;
      
          @end
      
    • XMGDeal.m

          @implementation XMGDeal
      
          + (instancetype)dealWithDict:(NSDictionary *)dict {
      
              XMGDeal *deal = [[self alloc] init];
              [deal setValuesForKeysWithDictionary:dict];
              return deal;
          }
      
          @end
      
    • XMGDealCell.h

          @class XMGDeal;
      
          @interface XMGDealCell : UITableViewCell
      
          /** 模型数据 */
          @property (nonatomic, strong) XMGDeal *deal;
      
          @end
      
    • XMGDealCell.m

          @interface XMGDealCell()
      
          @property (weak, nonatomic) IBOutlet UIImageView *iconView;
          @property (weak, nonatomic) IBOutlet UILabel *titleLabel;
          @property (weak, nonatomic) IBOutlet UILabel *priceLabel;
          @property (weak, nonatomic) IBOutlet UILabel *buyCountLabel;
      
          @end
      
          @implementation XMGDealCell
      
          - (void)setDeal:(XMGDeal *)deal {
      
              _deal = deal;
      
              // 设置数据
              self.iconView.image = [UIImage imageNamed:deal.icon];
              self.titleLabel.text = deal.title;
              self.priceLabel.text = [NSString stringWithFormat:@"¥%@", deal.price];
              self.buyCountLabel.text = [NSString stringWithFormat:@"%@人已购买", deal.buyCount];
          }
      
          @end
      
    • XMGDealsViewController.m

          @interface XMGDealsViewController ()
      
          /** 所有的团购数据 */
          @property (nonatomic, strong) NSArray *deals;
      
          @end
      
          @implementation XMGDealsViewController
      
          - (NSArray *)deals {
      
              if (_deals == nil) {
      
                  // 加载plist中的字典数组
                  NSString *path = [[NSBundle mainBundle] pathForResource:@"deals.plist" ofType:nil];
                  NSArray *dictArray = [NSArray arrayWithContentsOfFile:path];
      
                  // 字典数组 -> 模型数组
                  NSMutableArray *dealArray = [NSMutableArray array];
                  for (NSDictionary *dict in dictArray) {
                      XMGDeal *deal = [XMGDeal dealWithDict:dict];
                      [dealArray addObject:deal];
                  }
      
                  _deals = dealArray;
              }
              return _deals;
          }
      
          #pragma mark - Table view data source
          - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
              return self.deals.count;
          }
      
          - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
      
              static NSString *ID = @"deal";
              XMGDealCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
      
              // 取出模型数据
              cell.deal = self.deals[indexPath.row];
      
              return cell;
          }
      
          @end
      

6.2 xib 自定义 cell

  • 创建一个继承自 UITableViewCell 的子类,比如 BookCell2。
  • 创建一个 xib 文件(文件名建议跟 cell 的类名一样),比如 BookCell2.xib。
    • 拖拽一个 UITableViewCell 出来。
    • 修改 cell 的 class 为 BookCell2。
    • 设置 cell 的重用标识。
    • 往 cell 中添加需要用到的子控件。
  • 在 BookCell2 中
    • 将 xib 中的子控件连线到类扩展中。
    • 需要提供一个模型属性,重写模型的 set 方法,在这个方法中设置模型数据到子控件上。
    • 也可以将创建获得 cell 的代码封装起来(比如 cellWithTableView: 方法)。
  • 在控制器中
    • 手动加载 xib 文件,或者利用 registerNib... 方法注册 xib 文件。
    • 利用重用标识找到 cell。
    • 给 cell 传递模型数据。

6.2.1 xib 创建 cell

  • 在 xib 文件中必须设置 Identifier 属性,否则 cell 不会被复用,会一直创建新的 cell,占用大量的内存。

  • Objective-C

    • BookCell2.xib

      图片 13

      • xib 的 Identifier 属性设置为 Book2ID
    • BookCell2.h

          @class BookModel;
      
          @interface BookCell2 : UITableViewCell
      
          // 定义 Cell 的数据模型
          @property (nonatomic, retain)BookModel *book;
      
          @end
      
    • BookCell2.m

          #import "BookCell2.h"
          #import "BookModel.h"
      
          @interface BookCell2 ()
      
          // 创建自定义 Cell 视图包含的内容
      
          // 按住 control 键拖动 或右键拖动过来生成
          @property (weak, nonatomic) IBOutlet UIImageView *iconView;         
          @property (weak, nonatomic) IBOutlet UILabel *titleLabel;
          @property (weak, nonatomic) IBOutlet UILabel *detailLabel;
          @property (weak, nonatomic) IBOutlet UILabel *priceLabel;
      
          @end
      
          @implementation BookCell2
      
          // 设置显示的数据
      
          - (void)setBook:(BookModel *)book {
      
              _book = book;
      
              // 设置数据,设置 cell 视图上显示的内容 内容
              self.iconView.image = [UIImage imageNamed:book.icon];
              self.titleLabel.text = book.title;
              self.detailLabel.text = book.detail;
              self.priceLabel.text = book.price;
          }
      
          @end
      
    • ViewController.m

          // 使用 xib 定义的 Cell 创建,UITableViewDataSource 协议方法
          - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
      
              // 使用 xib 定义的 Cell 定义
              BookCell2 *cell = [tableView dequeueReusableCellWithIdentifier:@"Book2ID"];
      
              if (cell == nil) {
      
                  // 通过 xib 文件创建新的 cell
                  cell = [[[NSBundle mainBundle] loadNibNamed:@"BookCell2" owner:self options: nil] lastObject];
              }
      
              BookModel *bookModel = [self.myDataArray objectAtIndex:indexPath.row];
              cell.book = bookModel;
      
              return cell;
          }
      
  • Swift

    • BookCell2.xib

      图片 14

      • xib 的 Identifier 属性设置为 Book2ID 。
    • BookCell2.swift

          class BookCell2: UITableViewCell {
      
              // 创建自定义 Cell 视图包含的内容
      
              @IBOutlet weak var iconView: UIImageView!
              @IBOutlet weak var titleLabel: UILabel!
              @IBOutlet weak var detailLabel: UILabel!
              @IBOutlet weak var priceLabel: UILabel!
      
              // 设置显示的数据
      
              func configWithModel(bookModel:BookModel){
      
                  // 设置数据,设置 cell 视图上显示的内容 内容
                  iconView!.image = UIImage(named: bookModel.icon!)
                  titleLabel!.text = bookModel.title
                  detailLabel!.text = bookModel.detail
                  priceLabel!.text = bookModel.price
              }
          }
      
    • ViewController.swift

          // 使用 xib 定义的 Cell 创建,UITableViewDataSource 协议方法
          func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
      
              // 使用 xib 定义的 Cell 定义
              var cell:BookCell2? = tableView.dequeueReusableCellWithIdentifier("BookCell2") as? BookCell2 
      
              if cell == nil {
      
                  // 通过 xib 文件创建新的 cell
                  cell = NSBundle.mainBundle().loadNibNamed("BookCell2", owner: self, options: nil).last as? BookCell2
              }
      
              let bookModel:BookModel = self.myDataArray[indexPath.row]
              cell!.configWithModel(bookModel)
      
              return cell!
          }
      

6.2.2 xib 注册 cell

  • 如果 cell 使用 xib 注册的方式,xib 中可以不指定复用标识 Identifier 属性,如果 xib 中指定了,那么所有地方都要同步。但无论如何代码中必须设置 Identifier 属性。

  • 在 tableView 创建时,从 iOS7 开始多了一种创建 cell 的方式(注册),让 tableView 注册一种 cell,需要设置复用标志。

  • 用注册方式创建 cell,如果 tableView 已经注册了某一种 cell,从复用队列里查找,如果找不到,系统会自动通过注册的 cell 类来创建 cell 对象。

  • Objective-C

    • BookCell2.xib
    • BookCell2.h
    • BookCell2.m

      • xib 自定义 Cell 部分同上。
    • ViewController.m

          // 注册 cell
          [myTableView registerNib:[UINib nibWithNibName:NSStringFromClass([BookCell2 class]) bundle:nil] forCellReuseIdentifier:@"Book2ID"];
      
          // 使用注册的 xib cell 创建,UITableViewDataSource 协议方法
          - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
      
              // 使用 xib 定义的 Cell 定义
              BookCell2 *cell = [tableView dequeueReusableCellWithIdentifier:@"Book2ID" forIndexPath:indexPath];
      
              BookModel *bookModel = [self.myDataArray objectAtIndex:indexPath.row];
              cell.book = bookModel;
      
              return cell;
          }
      
  • Swift

    • BookCell2.xib
    • BookCell2.swift

      • xib 自定义 Cell 部分同上。
    • ViewController.m

          // 注册 cell
          myTableView.registerNib(UINib(nibName: "BookCell2", bundle: nil), forCellReuseIdentifier: "Book2ID")
      
          // 使用注册的 xib cell 创建,UITableViewDataSource 协议方法
          func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {           
              // 使用 xib 定义的 Cell 定义
              let cell:BookCell2? = tableView.dequeueReusableCellWithIdentifier("Book2ID", forIndexPath: indexPath) as? BookCell2
      
              let bookModel:BookModel = self.myDataArray[indexPath.row]
      
              cell!.configWithModel(bookModel)
      
              return cell!
          }
      

版权声明:本文由龙竞技官网发布于竞技宝app,转载请注明出处:UITableView,你了解多少?