客户端骨架屏详解

简介: 客户端骨架屏详解

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

对于菊花图我们自不必多说,现在对于加载的设计体验有了比菊花加载体验更棒的方法,即大家常看到的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,正常显示。

特点

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

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

Somo

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

特点

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

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

TABAnimated

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

1,Install

pod search TABAnimated

1

2,第二步(可选)

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

// 设置TABAnimated相关属性

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

1

2

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             // 结束动画

};

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

// 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;

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

4,第四步

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

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

typedef enum {

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

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

   TABViewLoadAnimationLong         //动画先变长再变短

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

1

2

3

4

5

{

       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];

}

1

2

3

4

5

6

7

8

9

10

11

5,第五步

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

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

_mainTV.animatedStyle = TABTableViewAnimationEnd;

[_mainTV reloadData];

   

_headView.animatedStyle = TABViewAnimationEnd;

[_headView initWithData:headGame];

1

2

3

4

5

6

示例源码链接: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

前端

在前端中,通过 puppeteer 在服务端操控 headless Chrome 打开开发中的需要生成骨架屏的页面,在等待页面加载渲染完成之后,在保留页面布局样式的前提下,通过对页面中元素进行删减或增添,对已有元素通过层叠样式进行覆盖,这样达到在不改变页面布局下,隐藏图片和文字,通过样式覆盖,使得其展示为灰色块。然后将修改后的 HTML 和 CSS 样式提取出来,这样就实现了骨架屏。

相关文章
|
移动开发 前端开发
前端(十八):移动端H5调用摄像头拍照旋转解决方案
移动端H5调用摄像头拍照旋转解决方案
342 0
|
3月前
|
API
【threejs教程】场景视角切换的神器:轨道控制器
【8月更文挑战第5天】threejs教程:场景视角切换的神器,轨道控制器
176 1
【threejs教程】场景视角切换的神器:轨道控制器
|
4月前
|
JavaScript 前端开发 开发者
uniapp实战 —— 骨架屏
uniapp实战 —— 骨架屏
135 0
|
6月前
简约火箭发射静态404错误页面源码
简约火箭发射静态404错误页面源码
47 0
简约火箭发射静态404错误页面源码
|
6月前
|
前端开发 JavaScript 小程序
轻量级骨架屏设计,让你的页面“薄荷清新”
轻量级骨架屏设计,让你的页面“薄荷清新”
HMI-31-【运动模式】解决音乐模块图片显示问题
上一篇中,我们基本实现了音乐模块的布局显示,但是留了个小尾巴,就是图片显示,这个模块中,图片不是方正的,而是有透视的,但是呢,Qt的图像显示显示,我还没有研究那么深入,所以目前只能是像,但是肯定不是真真的透视。我是利用遮罩来实现的,其实还是平面的图片,仅仅是用了一个透视的图片模版来覆盖一下。
HMI-31-【运动模式】解决音乐模块图片显示问题
|
6月前
|
vr&ar C# 图形学
【Unity 3D】VR飞机动态拆装及引擎开关控制案例(附源码和演示视频 超详细)
【Unity 3D】VR飞机动态拆装及引擎开关控制案例(附源码和演示视频 超详细)
106 0
|
Web App开发 编解码 移动开发
探秘移动端网页调用摄像头的两种方式
PC 端网页调用摄像头的场景想必大家并不陌生,打开一个网址,开启摄像头开始笔试/视频聊天/直播等。 而在移动端网页调用摄像头的场景你见得多吗?我想答案应该是不多吧(在下见识浅薄)。
|
JavaScript 前端开发 程序员
【前端】使用jQuery实现静态布局地铁线路地图和自动点亮站点
前段时间,看到有这样一篇文章,标题写着,jQuery是不是过时了!个人觉得,这是技术迭代更新过程中无法避免的,也是一种进步。能发出如此感概,说明已经有新的技术框架逐渐占据了一定的使用量。 技术框架会不会过时,这个并不是最重要的,重要的是能够以技术框架作为辅助,理解和掌握他们的原理,进而实现自己目标功能。功能实现逻辑基本上不会变 jQuery也是有自己得优势,在javascript基础上封装的函数库,更方便控制DOM对象,也可以快速使用jQuery锻炼自己的前端编程逻辑
367 0
|
JavaScript 前端开发
封装一个视频组件(可模拟画中画效果)
封装一个视频组件(可模拟画中画效果)
封装一个视频组件(可模拟画中画效果)