美文网首页程序员
我对tableView的一些理解

我对tableView的一些理解

作者: senpaiLi | 来源:发表于2018-10-21 23:35 被阅读2次

    一、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的展示类布局基本就算是可以出师了。
    当然了,学无止境。

    相关文章

      网友评论

        本文标题:我对tableView的一些理解

        本文链接:https://www.haomeiwen.com/subject/vxsuzftx.html