骨架屏TABAnimated源码解析

骨架屏Git地址(https://github.com/tigerAndBull/TABAnimated)

在看源码分析前,看一下Git上的ReadMe和Documents下的文档,最好能够使用过TABAnimated。

TABAnimated 目录结构

TABAnimated                     
    -Core
        -TABAnimated.h (全局属性配置等)
        -Cache (缓存模块)
        -Animation (添加动画模块)
        -Category (为View添加TAB管理和动画的开启关闭等模块)
        -Manager (骨架的生成、配置、管理)
        -Model(View、TableView、CollectionView初始化对象)
    -Reveal (输入条件,实时查看代码的工具)

分析模块

本文不对Reveal和Cache进行分析。
Reveal没有仔细使用。Cache原理可以参考作者的原文:缓存策略

对于骨架屏的生成原理,View、TableView、Collection基本流程都是一样的。先只针对TableView进行探索吧。

一句话解释TABAnimated原理

利用Runtime交换方法原理,交换TableView的Delegate、DataSoure代理的相关方法成框架内的tab_开头的方法,在cellForRow的方法中,遍历cell的subViews,通过UIView的convertRect:fromView方法得到相关subview的CGRect,然后使用贝塞尔曲线和CAShapeLayer构成骨架,添加到layer层上,完成骨架的构建。

按流程解析源码

初始化

 _tableView.tabAnimated = [TABTableAnimated animatedWithCellClass:[TestTableViewCell class]
        cellHeight:90];

1.通过Category文件下的UIView+TABAnimated.h 为UITablView添加了tabAnimated属性(runtime添加),然后使用了Model文件下的TAbTableAnimated.h的tablview的TAb初始化方法。

2.传入的参数主要用于tab_开头的tbalview代理的实现。[cell class]和cell height嘛。

开启骨架屏

 [tableView tab_startAnimation];

1.tab_startAnimation 是Category文件下UIView+TABControlAnimation.h的方法,该文件主要控制骨架屏的显示和关闭等操作事件。

2.tab_startAnimation中判断了一下动画状态,然后调用了

- (void)startAnimationIsAll:(BOOL)isAll
                      index:(NSInteger)index 

该方法中,对View、TableView、CollectionView进行了分别的判断处理,针对TableView,首先通过

[tabAnimated exchangeTableViewDelegate:tableView];
[tabAnimated exchangeTableViewDataSource:tableView];

对tableview的Delegate和DataSource进行了方法交换。然后遍历了初始化时传入的[cell class] array 对tablview进行cell的register,接着处理预估高度和headerView、footerView,最后查看一下是否有指定row显示骨架的需求,然后reload tablview。

3.reload之后,因为交换了方法,所以会走tab_开头的代理方法。相关代理方法在TABTableAnimated.m文件中。
主要看一下tab_tableView:cellForRowAtIndexPath:方法

首先通过runMode属性确定了index。根据index判断section或者row是否需要显示骨架

    if ([tableView.tabAnimated currentIndexIsAnimatingWithIndex:index]) {
        ...
    }
    return [self tab_tableView:tableView cellForRowAtIndexPath:indexPath];

,需要则进入if,不需要则

return [self tab_tableView:tableView cellForRowAtIndexPath:indexPath];

显示原来的tablview的界面。在if中,通过cell class 的array 取得Tableviewcell。然后为cell 初始化tabComponentManager属性

[TABManagerMethod fullData:cell];

fullData方法为subView添加假数据,调整骨架图形的位置。
最后通过

[TABManagerMethod runAnimationWithSuperView:tableView
                                                         targetView:weakCell
                                                             isCell:weakCell
                                                            manager:weakCell.tabComponentManager];

显示骨架。

TABManagerMethod

上一步中调用了runAnimationWithSuperView这个方法显示了骨架。
在这个方法中,首先根据状态确定是要显示骨架,还是结束骨架显示。
在显示骨架的if分支中,有三个主要的方法

//1.
[TABManagerMethod getNeedAnimationSubViews:targetView
                                     withSuperView:superView
                                      withRootView:targetView
                                 withRootSuperView:superView
                                      isInNestView:NO
                                             array:array];

//2.
 [targetView.tabComponentManager installBaseComponentArray:array.copy];
 
 //3.
  [targetView.tabComponentManager updateComponentLayers];

在第一个方法中,通过递归,为每个subview都生成了layer加入到array中, 在递归过程中,对于一些特殊的和需要过滤的视图,添加了过滤标记needRemove。通过needRemove为layer的loadStype标记为Remove,在第三个方法添加的时候会跳过。

在第二个中,将第一个方法生成的layer的array赋值给manager的componentLayerArray,和生成BaseComponentArray

在第三个方法中,把BaseComponentArray中的对象持有的layer添加到tabLayer上,显示出来
至此 显示逻辑基本结束

关闭骨架屏

    [self.tableView tab_endAnimationEaseOut];

通过这个方法,修改动画状态,并且将runAnimationIndexArray移除所有元素,重新reload显示原本的tableview;

[tabAnimated.runAnimationIndexArray removeAllObjects];

因为在tab_tableview:cellForRow
方法中,通过

[tableView.tabAnimated currentIndexIsAnimatingWithIndex:index]

进行了if 分支判断当runAnimationIndexArray没有元素时,会执行原本的tableview:cellForRowAtIndexPath.

未分析模块

  1. 缓存模块
  2. collectionView、View模块(流程应该差不多和tablview)
  3. 链式语法模块
  4. 动画模块(闪光灯,豆瓣动画等)

你可能感兴趣的:(骨架屏TABAnimated源码解析)