心想事成 UITableView 以及想。UITableView

心想事成 UITableView 以及想。UITableView

前言

如出一辙年前因 UITableView 无法满足急需,我实现了接近 UITableView
的组件, DLTableView

因而实现一个自定义的 UITableView,是因自急需一个可知顶循环滚动的
TableView。

习以为常的做法是安 dataSource 的 numberOfRowsInSection:
方法返回尽量多的行数,然后于针对 row
取余坐贯彻看起是最为循环滚动的特效。UIDatePicker 就是这样子实现之。

这种方案来只问题,如果用户直接为生滚动,还是会滚动到底的,所以行数要安装的玩命生。另一方面太怪的行数会导致内存以暴涨。
UIDatePicker 的做法是安装一个成立之行数,在用户已滚动的当儿失去校正
contentOffset,由于无动画效果,用户无法感知,在内存和法力之间赢得了平衡。但是连向下滚动的语,你晤面发现还是能滚到脚,等而再次入的早晚才会重置一下
contentOffset。所以这方案并无完善。

因为许多因最终自己主宰实现一个 UITableView。好处来几乎单:

  1. 自从执行备受构思苹果是哪些实现的,有啊困难,它的 UITabeleView
    有啊得改善之处在。这些不是独自的羁押几乎篇博客或者直接看源码就足以落的
  2. 贯彻一个基本的 TableView 之后,可以添加诸多原生 TableView
    不具的功用,比如说循环滚动特性。项目推行可以进一步灵敏
  3. 好依据新的自定义的 TableView 实现一个比官方
    UIPickerView/UIDatePicker 更好的 DLPickerView

这里先主一下,下一样篇我会讲解如何根据 DLTableView 实现
DLPickerView。这个 pickerView 有瞬间特色:

  1. 类似 UITableView 的 delegate 和 dataSource,同时可以起定义
    cell,用法了类似 UITableView,灵活性更胜似。
  2. 得设置连续的可选区域,用户不能够滚动到可摘区域外
  3. 足配备循环滚动或者未循环滚动
  4. DLPickerViewDelegate 提供对每个 cell 基于目前职的视图自定义

DLTableView
的 GitHub 地址是
https://github.com/danleechina/DLTableView。

脚开始称如何促成一个自定义的 TableView。

目录

  • 安装协议
  • 创建cell
  • 用nib创建cell
  • UITableViewDataSource
  • UITableViewDelegate
  • 常用属性
  • 不常用性
  • TableView滚动时调用的艺术
  • titles索引列

UITableView 继承 UIScrollView
//获取选中的cell
self.myTableView.indexPathForSelectedRow.row

关键点

于定义 TableView 的实现有星星点点只根本点:

  1. Cell 复用
  2. 找到实现的切入点

Cell 复用比较好理解,因为内存是少数的,不可能无限多的生成 Cell 实例。

Cell 复用的兑现呢比较简单,给每种 Cell 类设置一个
identifier,以这个为键,值为一个饱含该 Cell 类的 set 集合。Cell
滚来而视域时候加到 set 里面,Cell 出现在可视域时于 set
里面获取一个,如果 set 里面没的讲话虽然十分成一个。

那切入点呢?

第一,我们的自定义 DLTableView 是基于 UIScrollView
的,UIScrollView
提供了颇好之轮转效应,虽然当采用的时发现尚是产生接触未顶满意的地方,比如以动画片的道设置
contentOffset
时没法做到设置一个完动画的回调,还有即使是如对滚动的拦路虎做调整。

今昔求想想一个题目,在什么时为 DLTableView 添加一个 Cell,也就是说将
Cell 作为 TableView 的子视图或者后人视图?以及当 Cell
从用户视线被流失时拿 Cell 从 DLTableView
中移除,并参加到复用的队列中?

先是想到的凡 scrollViewDidScroll:,在 UIScrollView 滚动的时段添加
Cell。但是 scrollViewDidScroll 是代理实现的,作为连续自 UIScrollView
DLTableView 本身不应有实现者代理。而且在 contentSize 未知的时
UIScrollView 可能根本无克滚动。

自我们好 hook 掉 UIScrollViewsetDelegate: 方法,然后在起定义
TableView 里面实现有 UIScrollViewDelegate
的措施,在这些方法中再回调给采用于定义 TableView 的 delegate。天猫的
LazyScrollView
就是这么实现之 (不过她才复写了 scrollViewDidScroll:
方法,其他方式是透过动态转发来落实的)。这种方案的通病是一旦手动设置
contentSize

我当时边的落实是使 layoutSubviews。每次初始化的早晚,UIView
都见面调用该措施,在是点子中我们可初始化最初的可见 Cell,以及
contentSize。灵感来源和苹果之法定
demo:StreetScroller

另外,当 UIScrollView
滚动的下,会频之调用该方式。这样咱们即便可以动态的以 Cell 加入或者去丢。

此地补充某些,有时候 scrollViewDidScroll:
的调用频率没我们怀念的那么基本上之时光,你也可实现
layoutSubviewslayoutSubviews 的频率比 scrollViewDidScroll:
高,当然绝不忘记调用 [super layoutSubviews]

安装协议

1.创建tableView对象

 UITableViewStylePlain,  (默认)扁平风格(也是可以分组)
 UITableViewStyleGrouped  分组

 tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];

 //2.显示在界面上
 [self.view addSubview:tableView];

落实细节

  1. TableView 可能会见起 header 或者 footer,所以当测算高度的时刻每个 cell
    的职要丰富 header 高度的皇,计算 contentSize
    的惊人的当儿要加上 footer 的可观。
  2. TableView 可以无单独发 row 还可更加区分每个
    section,关键一点凡是每个 section 也堪发 header 和 footer,所以计算
    cell 的职务的时光会时有发生那么一些无直观,同时 section 的 header 和
    footer 在 TableView 中的岗位是滚的,到到的时段还要是悬浮在 row
    上面,这同碰而留意。
  3. UITableView 支持将有 Cell 滚动到顶部,自定义的当儿可以设想用 Cell
    滚到到、中、底。
  4. 点击。一般不见面以每个 Cell 里面加一个 tap gesture
    recognizer。我的做法是于 TableView 层面加一个 Tap gesture
    recognizer,这样每次识别到点击的时刻,可以具体分配至有
    cell。当然还有设置点击效果(比如 cell 点击变灰)。
补偿:UICollectionView底部叫标签了控制器(tabBar)遮挡的解决办法
//
 self.collectionV = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 0, self.view.width, self.view.height-44) collectionViewLayout:flowLayout];

 self.automaticallyAdjustsScrollViewInsets = NO;
 self.collectionV.contentInset = UIEdgeInsetsMake(44, 0, 0, 0);

3.设置代理
多少有关的代理(只有实现dataSource的协商章程,才能够当tableView上去显示数据)

//声明协议
 @interface ViewController ()<UITableViewDataSource>

//设置代理
 tableView.dataSource = self;

DLTableView

本身当下边贯彻了一个自定义 TabelView,DLTableView

目前 DLTableView 实现之特点有:

  1. 类似 UITableViewDataSource
    DLTableViewDataSource,使用者可以兑现 dataSource
    来自定义行数和各个一行的 cell
  2. 类似 UITableViewDelegate
    DLTableViewDelegate,目前带有点击逻辑、自定义高度与某某 Cell
    滚来可观望区域时段的回调
  3. 可以循环滚动,同时内存以非会见产出暴涨(比如 UITableView
    就会涨)
  4. 点击某平执行得滚动到到、中、底

而可用 DLTableView 看做是一个简化版的 UITableView,它并未
section,只有 row,也尚未落实每个行之分割线,更无实现 UITableView
里面的左滑 cell 自定义菜单这些效应,而且手上还无支持自动计算行高。

可是出于 DLTableView
的贯彻是开源可见的,所以你可以依据这举行越来越的自定义。

UITableViewDataSource

非得贯彻之说道方式

更好的 TableView

面说了那基本上,都是以说什么实现一个近似 UITableView
TableView,主要是山寨。

那哪些根据山寨版的 TableView,提供一个重好的 TableView ?

率先什么叫更好之 TableView ?我收拾了如下:

  1. 机关测算和缓存 Cell 高度,市面上出诸多息息相关开源代码,你可以查。
  2. 异步构建视图,以及加载数据,参考 AsyncDisplayKit(Texture) 的思索。
安装每组的个数

返回值:设置分组中的行数(每组cell的个数)
参数1:委托
参数2:第几组

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{

    //需要每一组显示100条数据
    return 100;
}

引用

  1. StreetScroller
  2. iOS 异构滚动视图 LazyScrollView
    一些实现细节的入木三分解读
  3. LazyScrollView
Cell(tableView显示数据,也无是由此tableView本身去展示数据,而是经过cell来显示)

返回值:创建好之cell
参数1:委托
参数2:cell的职(和坐标没有关联,只跟组和行有关)

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

  !!!!!面试过程中常问的问题:
  1.去复用池中查看是否有可以复用(重复使用)的cell;如果有就返回可以复用的cell地址,没有返回nil
   参数:复用ID
 UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"cellId"];

  2.判断是否拿到可以复用cell,如果没有拿到就创建一个新的cell(最终创建cell的个数是整屏显示的cell的个数加1或者加2)
    if (cell==nil) {
    参数1:风格
    参数2:复用ID

   cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"cellId"];
    }

  3.刷新数据(刷新cell上显示的内容)
   indexPath由section(组)和row(行)组成
    cell.textLabel.text = [NSString stringWithFormat:@"第%ld组,第%ld行", indexPath.section, indexPath.row];

   4.返回cell
   return cell;

}

安装cell的入选样式

//UITableViewCellSelectionStyleNone没有选中的效果
 [cell setSelectionStyle:UITableViewCellSelectionStyleNone];

nib定制Cell

让TableView先注册nib

 // 注册单元格
 [_tableView registerNib:[UINib nibWithNibName:@"SubjectCell" bundle:nil] forCellReuseIdentifier:SubjectCellIdentifier];

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
  // 复用单元格
  SubjectCell * cell = [tableView dequeueReusableCellWithIdentifier:SubjectCellIdentifier forIndexPath:indexPath];

  // 获取数据模型
  SubjectModel * model = self.subjectArray[indexPath.row];

  cell.model = model;

  return cell;
}

设置tableView的分组数(默认是1独分组)
参数:委托

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

    return 3;  
}

可是选商

设置header的标题

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

    switch (section) {
        case 0:
            return @"热门";
            break;

        case 1:
            return @"最近更新";
            break;

        case 2:
            return @"销量最高";
            break;

        default:
            break;
    }
    return @"头标题";
}

设置footer的标题

- ( NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section{

    return @"脚标题";

}

UITableViewDelegate

MARK高度相关

设置Cell行高

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{

        return 50; 
}
入选相关

入选一个cell的时段会调用这个法子

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{

    NSLog(@"cell被选中");
    //在这儿跳转到下一个界面
    NextViewController * next = [[NextViewController alloc] init];

    //传值
    next.indexpath = indexPath;


    //push到下一个界面
    [self.navigationController pushViewController:next animated:YES];

    //present到下一个界面
    [self presentViewController:next animated:YES completion:nil];

}
头视图和脚视图相关

设置header高度

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
//    return 50 * section + 10;
    return 50;
}

设置Footer高度

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{

    return 50;
}

安各一样组的headerView

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{

   //创建一个视图(设置frame无效)
   UIView * headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
   //设置背景颜色
   headerView.backgroundColor = [UIColor redColor];

   //创建一个label
   UILabel * label = [[UILabel alloc] initWithFrame:CGRectMake(30, 0, 200, 50)];
   label.text = [NSString stringWithFormat:@"头标题:%ld", section];
   [headerView addSubview:label];

   return headerView;

}

装每组脚视图Footer

- (nullable UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section{

    //创建一个视图(设置frame无效)
    UIView * headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
    //设置背景颜色
    headerView.backgroundColor = [UIColor yellowColor];


    //创建一个label
    UILabel * label = [[UILabel alloc] initWithFrame:CGRectMake(30, 0, 200, 50)];
    label.text = @"脚标题";
    [headerView addSubview:label];


    return headerView;

}

Cell的附件相关

设置指定位置的cell的附件类型
  cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;

    UITableViewCellAccessoryNone,(默认)
    UITableViewCellAccessoryDisclosureIndicator 一个小箭头(常用)
    UITableViewCellAccessoryDetailDisclosureButton 一个详情按钮加小箭头
    UITableViewCellAccessoryCheckmark,  一个蓝色勾
    UITableViewCellAccessoryDetailButton  一个详情按钮
补充加了箭头以后,若还想以箭头前面添加文字

http://www.th7.cn/Program/IOS/201410/289058.shtml

cell.detailTextLabel.text = @"mona";
如果你执行之后可以看到箭头前有文字出现的话,那么恭喜你,你是幸运的。
我就没那么幸运,改了很多次之后都cell右侧都没有显示过文字出来,后来就根据这个情况,找了很久都没找到相应的解决方法。
后来在一段demo中才知道,原来要在右侧显示出detailTextLabel的文字,还需要在cellForRowAtIndexPath:中把cell的类型设置为

UITableViewCellStyleValue1,cellForRowAtIndexPath:的整段代码如下:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{    
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"formCell"];    
 if (cell == nil) {       
 cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"formCell"];       
 cell.textLabel.text = @"monalisa";   
  }    
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.detailTextLabel.text = @"mona";

betway必威 1

附件上之按钮被点击后调用这个法子
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath{

    NSLog(@"附件按钮被点击");
}
将要显示一个cell的时段会调用这个点子
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{

    NSLog(@"将要显示cell");
}

常用属性

1.行胜过(每一行的惊人都是200)

 tableView.rowHeight = 200;

2.分组的header和footer的高度

 tableView.sectionHeaderHeight = 100;
 tableView.sectionFooterHeight = 100;

3.安分割线的体制

 UITableViewCellSeparatorStyleNone,     (隐藏分割线)
 UITableViewCellSeparatorStyleSingleLine,
 UITableViewCellSeparatorStyleSingleLineEtched

 [tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone];

4.手动刷新数据(自动刷新是于开创与滑动tableView的时betway必威)—刷新会重新调用dataSource中创造cell的方去重新创设cell

//刷新所有的cell
[tableView reloadData];


 //刷新指定的组
 NSIndexSet *indexSet=[[NSIndexSet alloc]initWithIndex:5];
 [self.tableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationAutomatic];

//刷新指定的row
[self.tableView reloadRowsAtIndexPaths:<#(nonnull NSArray<NSIndexPath *> *)#> withRowAnimation:<#(UITableViewRowAnimation)#>]

5.以视图添加至Header上,只能添加一个

 UIView * view = [[UIView alloc]initWithFrame:CGRectMake(100, 100, 100, 100)];

 view.backgroundColor = [UIColor yellowColor];
    [tableView setTableHeaderView:view];

6.安装情节偏移

[tableView setContentInset:UIEdgeInsetsMake(100, 0, 0, 0)];

7.获取cell在当前TabView中的indexPath

 NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];

8.点击后销cell选中成效

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

不常用性

1.安分割线的边距

[tableView setSeparatorInset:UIEdgeInsetsMake(50, 50, 50, 50)];

2.安分割线的水彩

  [tableView setSeparatorColor:[UIColor redColor]];

3.拿走指定的坐标点所在的职位(第多少组第几履)

 - ( NSIndexPath *)indexPathForRowAtPoint:(CGPoint)point;

4.获得到指定位置(第几组第几尽)对应的cell

 - ( UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath

5.获取当前界面及可见的具有的cell

 //@property (nonatomic, readonly) NSArray *visibleCells;

6.d

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;

6.滚动到指定位置
参数1: 指定的职
参数2: 滚动位置

- (void)scrollToRowAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated;

7.将当选的cell滚动到指定位置(顶部底部或中间)

- (void)scrollToNearestSelectedRowAtScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated;

8.刷新指定位置的cell

- (void)reloadRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation

9.选中指定的职

- (void)selectRowAtIndexPath:(nullable NSIndexPath *)indexPath animated:(BOOL)animated scrollPosition:(UITableViewScrollPosition)scrollPosition;

TableView滚动时调用的不二法门

当TableView滚动时会调用该方式

- (void)scrollViewDidScroll:(UIScrollView *)scrollView

当TableView停止滚动时见面调用该办法

 - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;

titles索引列

//设置背景颜色
 self.tableView.sectionIndexBackgroundColor = [UIColor clearColor];
//设置字体颜色 
self.tableView.sectionIndexColor = [UIColor blackColor];

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
    return self.indexArray;
}

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

    NSString *key = [self.indexArray objectAtIndex:section];
    return key;
}

- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
{
    return index;
}
admin

网站地图xml地图