美文网首页
客户端骨架屏详解

客户端骨架屏详解

作者: gang977 | 来源:发表于2019-11-28 15:54 被阅读0次

    一直以来,客户端的应用中,为了提升应用的加载等待这段时间的用户感知体验,各种技术层出不穷。其中,尤以菊花图以及由它衍生各种加载动画最为突出。

    对于菊花图我们自不必多说,现在对于加载的设计体验有了比菊花加载体验更棒的方法,即大家常看到的Skeleton Screen Loading,中文叫做骨架屏。

    所谓Skeleton Screen Loading,即表示在页面完全渲染完成之前,用户会看到一个占位的样式,用以描绘了当前页面的大致框架,加载完成后,最终骨架屏中各个占位部分将被真实的数据替换。很多项目中都有相关的应用,如饿了么h5版本、知乎、facebook等网站中都有应用。 其效果如下图所示:

    iOS

    iOS实现Skeleton效果的第三方库有很多,当然也可以自己创建一个,而骨架屏最核心的就是占位和属性动画。在实现方面,本文介绍几种主流的实现方式:

    SkeletonView

    实现原理

    对UIView进行扩展,增加skeletonable、skeletonLayer等属性。调用showSkeleton方法,对属性skeletonable为true的视图进行遍历,找到其最上层的、skeletonable为true的子View,然后创建skeletonLayer添加到上面,构成骨架图,动效效果亦是在skeletonLayer层。需要隐藏效果时,调用hideSkeleton,同样进行遍历,移除skeletonLayer。

    简单的说,在显示占位的时候,将tableView的代理设置为通过某个对象,这个对象根据cell的Idenfier创建cell并添加占位显示。关闭显示占位的时候,将代理tableView的代理切回ViewController,正常显示。

    特点

    1、不需手动写占位控件,不需处理圆角等问题,占位效果与实际控件布局一致。

    2、缺点是有的控件是自适应大小,在未获得数据之前,控件位置是错误的,导致占位效果有问题。

    Somo

    同样是扩展UIView,添加属性somoContainer,表示占位视图的容器视图,其中每个占位区域都是一个SomoView。对于想要显示占位效果的View,需实现协议,在协议方法中返回SomoView列表。将这些SomoView添加到somoContainer,并显示。

    特点

    1、避免了上述自适应控件无数据时大小不正确的问题。

    2、需要手工指定每个占位区域,且每个占位区域是UIView级别,不是CALayer。

    TABAnimated

    除此之外,TABAnimated也是一个被使用的比较多的,同样TABAnimated也是扩展的UIView。在ios中集成TABAnimated需要经历以下几步:

    1,Install

    pod 'TABAnimated'

    2,第二步(可选)

    可以选择在appDelegate的didFinishLaunchingWithOptions方法全局设置动画属性,设有默认属性。例如:

    // 设置TABAnimated相关属性

    [[TABViewAnimated sharedAnimated]initWithAnimatedDuration:0.3 withColor:tab_kBackColor];

    3,第三步,设置animatedStyle属性

    在需要动画的view上,将属性animatedStyle设置为TABTableViewAnimationStart,不需要动画的view不用做额外的操作。

    // UIView和UICollectionView枚举

    typedef NS_ENUM(NSInteger,TABViewAnimationStyle) {

        TABViewAnimationDefault = 0,              // 默认,没有动画

        TABViewAnimationStart,                    // 开始动画

        TABViewAnimationRuning,                    // 动画中

        TABViewAnimationEnd,                      // 结束动画

        TABCollectionViewAnimationStart,          // CollectionView 开始动画

        TABCollectionViewAnimationRunning,        // CollectionView 动画中

        TABCollectionViewAnimationEnd              // CollectionView 结束动画

    };

    // UITableView枚举

    typedef NS_ENUM(NSInteger,TABViewAnimationStyle) {

        TABViewAnimationDefault = 0,    // 没有动画,默认

        TABViewAnimationStart,          // 开始动画

        TABViewAnimationEnd            // 结束动画

    };

    // UITableView例子

    - (UITableView *)mainTV {

        if (!_mainTV) {

            _mainTV = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, kScreenHeight)];

            _mainTV.animatedStyle = TABTableViewAnimationStart;  // 开启动画

            _mainTV.delegate = self;

            _mainTV.dataSource = self;

            _mainTV.rowHeight = 100;

            _mainTV.backgroundColor = [UIColor whiteColor];

            _mainTV.estimatedRowHeight = 0;

            _mainTV.estimatedSectionFooterHeight = 0;

            _mainTV.estimatedSectionHeaderHeight = 0;

            _mainTV.separatorStyle = UITableViewCellSeparatorStyleNone;

        }

        return _mainTV;

    }

    // UIView例子

    - (TestHeadView *)headView {

        if (!_headView) {

            _headView = [[TestHeadView alloc]initWithFrame:CGRectMake(0, 0, tab_kScreenWidth, 90)];

            _headView.animatedStyle = TABViewAnimationStart;  //开启动画

        }

        return _headView;

    }

    4,第四步

    1、将需要动的组件的属性loadStyle,设置为需要的类型,不需要动的组件不用做额外的操作;

    2、(可选)新增属性tabViewWidth,其为动画开启时该组件的宽度,有较为合理默认值;

    typedef enum {

        TABViewLoadAnimationDefault = 0, //默认没有动画

        TABViewLoadAnimationShort,      //动画先变短再变长

        TABViewLoadAnimationLong        //动画先变长再变短

    }TABViewLoadAnimationStyle;          //view动画类型枚举

    {

            UILabel *lab = [[UILabel alloc]init];

            [lab setFont:tab_kFont(15)];

            lab.loadStyle = TABViewLoadAnimationLong;

            lab.tabViewWidth = 100;

            [lab setTextColor:[UIColor blackColor]];

            [lab setText:@""];

            titleLab = lab;

            [self.contentView addSubview:lab];

    }

    5,第五步

    在获取到数据后,停止动画。

    //停止动画,并刷新数据

    _mainTV.animatedStyle = TABTableViewAnimationEnd;

    [_mainTV reloadData];

    _headView.animatedStyle = TABViewAnimationEnd;

    [_headView initWithData:headGame];

    示例源码链接:iOS骨架屏示例

    Android

    在Android中,骨架屏的实现也后很多的第三方框架,常见的有以下几个库:

    ShimmerRecyclerView

    ShimmerRecyclerView是一个带有闪光和指示效果的库,其运行效果如下图:

    源码地址:https://github.com/sharish/ShimmerRecyclerView

    Skeleton

    Skeleton也是一个使用得比较广泛的库,它现在使用闪存动画的内存优化版本,因此速度更快,您也可以设置更大的布局动画。

    项目源码:https://github.com/ethanhua/Skeleton


    spruce-android

    Spruce 是一个轻量级动画库,可帮助编排屏幕上的动画,该库同时还支持 iOS。

    源码地址:https://github.com/willowtreeapps/spruce-android

    相关文章

      网友评论

          本文标题:客户端骨架屏详解

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