Tangram分析一LazyScrollView

2019-04-03  本文已影响0人  tom555cat

Tangram的组织结构

Tangram结构图

从Tangram结构图上看,主要分为页面(TangramView+TMlazyScrollView),布局(layout)和组件(element)三部分。页面是由继承自TMLazyScrollView的TangramView构成,TMLazyScrollView是一个独立的视图组件,本文主要内容为如何实现一个TMLazyScrollView。

模型

TMLazyItemModel

TMLazyItemModel是TMLazyScrollView中使用的基本模型,存储着TMLazyScrollView中的view对应的布局信息和唯一标识符,模型中包含的属性主要有:

  • 什么是muiID?
    muiID的是由这几部分构成的:
    layout.layoutType + model.itemType + model.reuseIdentifier + layout.layoutIdentifier + model.index(将lazyScrollView中的view视为同一层级之后的下标)
    这里的model就是lazyItemModel,由于与view一一对应,所以model的index与view的index也是一样的。

TMLazyModelBucket

TMLazyModelBucket是基本模型TMLazyItemModel上的一层封装,是比TMLazyItemModel层级更高的一个模型。是将origin.y在i*bucketHeight~(i+1)bucketHeight范围内的TMLazyItemModel放在一个集合里,然后所有的集合构成的一个数组。所以需要包含的属性主要有:

需要提供的方法应该包括:

控制器

TMLazyScrollView

TMLazyScrollView就是控制器,管理着的模型包括TMLazyModelBucket,TMLazyScrollView上的视图view,以及为了view重用而衍生的view唯一标识符muiID,所以包含的主要属性有:

下面是一些次要属性,主要用来保存业务处理过程中临时保存的数据,可以先放着不看。
* NSMutableSet<NSString *> *_needReloadingMuiIDs;    // 存储需要刷新内容的item对应的muiID
* NSSet<NSString *> *_lastInScreenVisibleMuiIDs;     // 存储上次可视范围内的TLMLazyItemModel的MuiIDs。
* NSMutableSet<NSString *> *_inScreenVisibleMuiIDs;  // 当前可视范围内的TMLazyItemModel的MuiIDs。

TMLazyScrollView还需要一个dataSource代理,代理需要实现一些方法用来提供一些必要的数据:

TMLazyScrollView对外提供的方法有:

reloadData方法的实现流程
  1. [self storeItemModelsFromIndex:0]
    清理所有本地数据;将所有的view对应的lazyModel存放进_modelBucket中,需要dataSource的方法1>和2>来提供lazyModel。

  2. -assembleSubviews:minY:maxY:
    统计当前可见范围内的model的muiID集合newVisibleMuiIDs。

2.1 -recycleItems:newVisibleMuiIDs: (isReload参数为YES)
遍历当前的可视view数组,_visibleItems

2.1.1 如果其中的view的muiID在将要出现的muiIDs集合newVisibleMuiIDs中,那么这个view只需要刷新其中的数据即可,将其muiID加入_needReloadingMuiIDs中。
2.1.2 如果其中的view的muiID不在将要出现的muiIDs集合newVisibleMuiIDs中,那么这个view就需要离开屏幕

2.1.2.1 此时需要调用view的mui_didLeave()方法
2.1.2.2 如果此view的reuseIdentifier.length>0,也就是说这个view是需要被重用的,那么就将其隐藏,并且加入reusePool中,将此element从_visibleItems数组中移除掉。
2.1.2.3 如果此itemView不打算重用,将其muiID加入_needReloadingMuiIDs中。

2.2 -generateItems: (isReload参数为YES)
获取view

2.2.1 对于_newVisibleMuiIDs中的任一muiID

2.2.1.1 如果不在_visibleItems中,或者需要刷新,则需通过代理dataSource的方法3>获取view,获取到itemView之后,(如何通过代理dataSource获取view?)【TMLazyScrollView如何通过代理获取element?】

2.2.1.1.1 调用view的方法mui_afterGetView
2.2.1.1.2 设置view的muiID,并设置hidden为NO,就是要让其显示出来,
2.2.1.1.3 如果该view之前没有显示在屏幕上,那么这次需要将其加入_visibleItems数组中
2.2.1.1.3 将其重_needReloadingMuiIDs中删除

2.2.1.2 对于newVisibleMuiIDs中的任一muiID,如果在_visibleItems中并且不需要刷新,那么不需要做其他操作

2.2.2 将muiID从_newVisibleMuiIDs总移除,如果_newVisibleMuiIDs不为空,则继续调用generateItems

reloadData流程中的-recycleItems:newVisibleMuiIDs:的处理流程可以用下图来表示:
reloadData流程中的-recycleItems:newVisibleMuiIDs:
reloadData流程中的-generateItems:的处理流程可以用下图来表示:
reloadData流程中的-generateItems:
setConentOffset方法的实现流程
  1. 用_lastContentOffset记录了上次滑动的contentOffset,当当前contentOffse.y和_lastContentOffset.y的差值绝对值大于LazyBufferHeight时,更新_lastContentOffset为当前的contentOffset,并调用assembleSubviews

  2. -assembleSubviews:minY:maxY:
    剩余流程同reloadData。

setConentOffset流程中的-recycleItems:newVisibleMuiIDs:的处理流程可以用下图来表示:
setConentOffset流程中的-recycleItems:newVisibleMuiIDs:
setConentOffset和reloadData的区别

区别在于recycleItem:newVisibleMuiIDs:中的第一个参数isReload,手动滑动isReload为NO,reloadData中的isReload为YES。

TMLazyScrollView通过self.dataSource获取view

具体调用流程为:
1 - (UIView *)scrollView:(TMLazyScrollView *)scrollView itemByMuiID:(NSString *)muiID
该方法是TangramView实现TMLazyScrollView的dataSource的3>代理方法,TangramView在实现中会调用VC实现的返回itemView代理方法

2 - (UIView *)itemInTangramView:(TangramView *)view withModel:(NSObject<TangramItemModelProtocol> *)model forLayout:(UIView<TangramLayoutProtocol> *)layout atIndex:(NSUInteger)index
这是VC需要实现的代理方法。在其中,可能会调用dequeueReusableItemWithIdentifier:方法, 调用的是TMLazyScrollView的方法dequeueReusableItemWithIdentifier:(muiID:)

2.1 - (UIView *)dequeueReusableItemWithIdentifier:(NSString *)identifier muiID:(NSString *)muiID
如果当前需要的(newVisibleMuiIDs中的muiID)view在屏幕上,则直接使用该view;
如果不在屏幕上,则从reusepool中拿一个,返回之;
如果什么也没有,则直接返回nil。

2.2 如果dequeueReusableItemWithIdentifier:返回结果非空,则用model去刷新该element。
reuseableView = [TangramDefaultDataSourceHelper refreshElement:reuseableView byModel:model layout:layout tangramBus:self.tangramBus];

2.3 如果dequeueReusableItemWithIdentifier:返回结果为空,则需要创建一个element,并用model数据去填充该element。
reuseableView = [TangramDefaultDataSourceHelper elementByModel:model layout:layout tangramBus:self.tangramBus];

从这个角度来看,TMLazyScrollView还需要实现一个重用view的方法,dequeueReusableItemWithIdentifier:(muiID:)

dequeueReusableItemWithIdentifier:(muiID:)方法实现流程
  1. 通过identifier从reusepool中查找view
    1.1 如果找到,调用view的prepareForReuse
  2. 返回找到的view或者nil

总结

模型:

控制器:

属性:
方法:
上一篇下一篇

猜你喜欢

热点阅读