美文网首页
骨架屏TABAnimated源码解析

骨架屏TABAnimated源码解析

作者: 蓝蓝蓝蓝蓝v | 来源:发表于2019-10-17 11:11 被阅读0次

    骨架屏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源码解析

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