程序员

我对tableView的一些理解

2018-10-21  本文已影响2人  senpaiLi

一、tableViewStyle的选择

tableview有两种style供我们选择,UITableViewStylePlain(默认)和UITableViewStyleGrouped。

1.grouped的sectionHeader不会悬浮。plain反之。

2.plain会出现多余的分割线,充满整个tableview,grouped不会。

具体选择那一种style,根据需求具体分析。个人比较喜欢UITableViewStylePlain,因为这样就不用再去专门做一个悬浮的sectionHeader,不会悬浮的header作为一个cell显示。

二、tableViewHeader

一般的页面都会有一个比较固定的头部,它们通常比较复杂,不用经常更新,UI数据也不用后台返回。这时候就需要我们的tableViewHeader。

tableViewHeader会随着tableView一起滑动。

tableViewHeader默认为nil,需要重新去赋值一个view;

需要注意的点:
通常我们习惯用masonry或者其他的一些自动化布局,但是tableViewHeader的高度,在layoutsubViews方法执行之前,默认为0。
所以我们需要在layoutsubViews之后,进行masonry布局,不然会报UI警告。(个人洁癖,其实无伤大雅)

另外一点,头部的图片,如果size超过了imageView的大小,记得设置maskToBounds,不然在ipad上面,会出现图片的溢出,遮挡住其他控件。

三、sectionHeader和cell

这两个一起说,其实在我看来,他们本质上是一致的:可以放到缓存池中被重用的view。
而tableView呢,是他们的一种布局方式,是collectionView的一种特殊布局,这个后面再说。

我只聊一下对cell的看法,sectionHeader可以比照着理解。

1、注册cell

比如注册一个LyTableViewCell,重用ID为LyTableViewCellId:

[tableView registerClass:[LyTableViewCell class] forCellReuseIdentifier:@"LyTableViewCellId"]

其实这是一个把LyTableViewCell注册到缓存池的操作,同样的,滑动tableView时释放cell,也会执行这个操作。
所以,你可以找到一个替代注册cell的方式:

LyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"LyTableViewCellId"];
if (!cell) {
  cell = [[LyTableViewCell alloc] init];
}

先从缓存池中取id为LyTableViewCellId的cell,如果为空,则初始化该cell。

2、cell的重用

每一个消失在屏幕上面的cell都会被放到缓存池中,等待被重用。
而重用这一操作,对我们原生开发来说,就是对一个cell重新赋值的过程。

比如对于一个cell,tabLabel可以是“半价”,可以是“精选”,也可以是隐藏状态,在我们重用时,就要充分考虑到所有cell的可能情况,对该cell进去相应的操作。
初学者出现的,cell的各种UI小问题,大部分都是这个原因。

重用时执行的方法:

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

大部分cell是需要重用的,这也是tableView在数据庞大时仍能保持高性能的原因。但是有些特殊的cell,比如"状态选择类"的,每次重新赋值,会导致状态的丢失,这时候就需要做一些特殊的操作,保证不被复用。

我的方式也很简单,在cellModel中,加一个singleIdentifier的属性,如果检测到,则不进行赋值,直接返回。(我习惯一个cell对应一个cellModel,如果大家没有这种习惯,其他类似方式也可以解决)

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
  {...}
  NSString *identifier = cellModel.singleIdentifier;
  BOOL forceRefresh = cellModel.forceRefresh;
  if (identifier && identifier.length > 0 && !forceRefresh)
  {
    return [tableView dequeueReusableCellWithIdentifier:identifier forIndexPath:indexPath];
  }
  {...}
}

这种写法会导致任何情况下都不会赋值,所以需要多加一个forceRefresh属性控制,是否强制刷新。

3、cell的点击

实现两个代理方法就可以了:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(3_0);

设置cell的selected为true之后,下次点击就会执行didDeselectRowAtIndexPath方法。

点击操作就在这里面执行。

如果要设置高亮状态的UI,则在cell的设置方法里面进行操作:

- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated;

四、代理方法

UITableViewDataSource:数据
传tableView的一些基础数据,如个数,cell数据;
负责cell的移动,删减,增加。

UITableViewDelegate:UI显示
遵循UIScrollViewDelegate;
负责如cell的显示,高度,预估高度,高亮状态,点击状态等等的回调;

为什么单拎出来说呢,因为这样我们可以明显的看到,苹果有意把tableView分成两个部分,数据和UI。
对应我们原生的工作,就是UI搭建和建模。
所以我们也可以把这两块分开来做,不要纠缠在一起。

数据由后台传递,是动态变化的。UI是我们自己搭建,相对格式化的,然后在tableView中对应起来。

这些大概就是小弟的一些浅见。
总有人觉得,tableView这么简单的东西,为什么还要专门去研究呢。但在我看来,见微知著,如果能把这个东西搞透彻,就有了去研究更深一级的collectionView的门槛,collectionView也琢磨透了,UI的展示类布局基本就算是可以出师了。
当然了,学无止境。

上一篇下一篇

猜你喜欢

热点阅读