Android仿搜狗浏览器加载动画

泡在网上的日子 发表于 2015-10-11 01:13   1089  次阅读  搜狗,加载动画
3

周六,国庆放假调休,今天闲来无事,就看了下搜狗浏览器的加载动画。感觉结合前面学习的基础还是能做出来的,所以就简单的实现了下,然后写下这边博客给大家参考参考,权当巩固基础。

我们先来看看搜狗的效果图,效果图是通过豌豆荚的屏幕截取的,由于公司电脑配置太差,用的Android Sutido导致卡的一笔。所以效果大家见谅了。有兴趣的可以下载个搜狗浏览器看看。 

20151010165041535.gif

参照效果图,无非就是简单的绘制一个圆然后搞点动画,所以结合前面博客的基础,是基本能做出来的,如果对动画还不是很熟悉的朋友,可以参照我的这篇博客来了解下。Android基础之Android动画

下面看看我们的效果图: 

20151010165130791.gif

还是比较像的,这里就提供个思路,具体的大家可以参照代码进行修改。下面简要说下里面涉及到的几个技术点。

技术点一:弹跳动画

这里我们使用的ValueAnimator进行动画的实现,不熟悉的同学,可以参照上面的博客。先来看看这部分的代码:

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
26
27
28
29
30
31
32
33
@Override
     protected void onDraw(Canvas canvas) {
         super .onDraw(canvas);
         //获取视图的中心点
         startX = getWidth()/2;
         endY =  getHeight() / 2;
         startY= endY * 5 / 6;
         mPaint.setColor(color);
         if (currentY == 0){
             playAnimator();
         } else {
             drawCircle(canvas);
             drawShader(canvas);
         }
     }
 
     //动画执行
     private void playAnimator(){
         //我们只需要取Y轴方向上的变化即可
         ValueAnimator valueAnimator = ValueAnimator.ofInt(startY,endY);
         valueAnimator.addUpdateListener( new  ValueAnimator.AnimatorUpdateListener() {
             @Override
             public void onAnimationUpdate(ValueAnimator animation) {
                 currentY = (Integer)animation.getAnimatedValue();
                 invalidate();
             }
         });
         valueAnimator.setInterpolator( new  AccelerateInterpolator(1.2f));
         valueAnimator.setRepeatCount(-1);
         valueAnimator.setRepeatMode(2);
         valueAnimator.setDuration(500);
         valueAnimator.start();
     }

为了掩饰效果,我们将View放置在视图中心,我们首先根据当前点是否为0进行判断,然后如果为0,我们执行属性动画。属性动画,我们只需要对Y轴变量进行变动处理即可,x轴无需关心,然后通过:

1
2
currentY = (Integer)animation.getAnimatedValue();
      invalidate();

进行刷新每次的视图,所以就开始绘制圆形了。同时为了处理到达底部有个压扁的效果,我用了绘制椭圆来处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  /**
      * 绘制圆形
      * @param canvas
      */
     private void drawCircle(Canvas canvas){
         //当接触到底部时候,我们为了要描绘一种压扁的效果
         if (endY - currentY >10){
             canvas.drawCircle(startX,currentY,radius * density,mPaint);
         } else {
             rectF =  new  RectF(startX - radius * density - 2,currentY - radius * density+5,
                     startX + radius * density+2,currentY + radius * density);
             canvas.drawOval(rectF,mPaint);
             Log.d(TAG, "Oval" );
         }
     }
技术点二:影子的处理

我们通过效果图发现,当球离的比较近的时候,会出现黑压压的影子,这里,我们采用的是绘制一个椭圆的效果来实现,按照常理,影子的大小也会随着高度的变化而变化,这里我是通过判断当前高度和总高度差的比率来计算,然后确定椭圆的范围进行绘制,这样就能达到椭圆的动态伸缩效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
      * 绘制阴影部分,由椭圆来支持,根据高度比来底部阴影的大小
      */
     private void drawShader(Canvas canvas){
         //计算差值高度
         int dx = endY - startY;
         //计算当前点的高度差值
         int dx1 = currentY - startY;
         float ratio = (float) (dx1 *1.0 / dx);
         if (ratio <= 0.3){ //当高度比例小于0.3,所在比较高的时候就不进行绘制影子
             return ;
         }
         int ovalRadius = (int) (radius * ratio * density);
         //设置倒影的颜色
         mPaint.setColor(Color.parseColor( "#3F3B2D" ));
         //绘制椭圆
         rectF =  new  RectF(startX-ovalRadius,endY+10,startX+ovalRadius,endY+15);
         canvas.drawOval(rectF,mPaint);
     }

这样就完成了全部的代码,是不是很简单,只要会点动画基础就能做出来了。

下面附上全部代码:

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
     /**
      * Created by shiwei.deng on 2015/10/10.
      */
     public class SoGouBrowserLoading extends View{
     private final String TAG =  "QQBrowserLoading" ;
     //画笔
     private Paint mPaint;
     //颜色
     private int color = Color.parseColor( "#0000FF" );
     //半径
     private int radius = 10;
     private float density;
     private RectF rectF;
     //起点、终点、当前点
     private int startY,startX,endY,currentY;
     public SoGouBrowserLoading(Context context, AttributeSet attrs) {
         super (context, attrs);
         density = getResources().getDisplayMetrics().density;
         mPaint =  new  Paint(Paint.ANTI_ALIAS_FLAG);
         mPaint.setStyle(Paint.Style.FILL);
     }
 
     @Override
     protected void onDraw(Canvas canvas) {
         super .onDraw(canvas);
         //获取视图的中心点
         startX = getWidth()/2;
         endY =  getHeight() / 2;
         startY= endY * 5 / 6;
         mPaint.setColor(color);
         if (currentY == 0){
             playAnimator();
         } else {
             drawCircle(canvas);
             drawShader(canvas);
         }
     }
 
     //动画执行
     private void playAnimator(){
         //我们只需要取Y轴方向上的变化即可
         ValueAnimator valueAnimator = ValueAnimator.ofInt(startY,endY);
         valueAnimator.addUpdateListener( new  ValueAnimator.AnimatorUpdateListener() {
             @Override
             public void onAnimationUpdate(ValueAnimator animation) {
                 currentY = (Integer)animation.getAnimatedValue();
                 invalidate();
             }
         });
         valueAnimator.setInterpolator( new  AccelerateInterpolator(1.2f));
         valueAnimator.setRepeatCount(-1);
         valueAnimator.setRepeatMode(2);
         valueAnimator.setDuration(500);
         valueAnimator.start();
     }
 
     /**
      * 绘制圆形
      * @param canvas
      */
     private void drawCircle(Canvas canvas){
         //当接触到底部时候,我们为了要描绘一种压扁的效果
         if (endY - currentY >10){
             canvas.drawCircle(startX,currentY,radius * density,mPaint);
         } else {
             rectF =  new  RectF(startX - radius * density - 2,currentY - radius * density+5,
                     startX + radius * density+2,currentY + radius * density);
             canvas.drawOval(rectF,mPaint);
             Log.d(TAG, "Oval" );
         }
     }
 
     /**
      * 绘制阴影部分,由椭圆来支持,根据高度比来底部阴影的大小
      */
     private void drawShader(Canvas canvas){
         //计算差值高度
         int dx = endY - startY;
         //计算当前点的高度差值
         int dx1 = currentY - startY;
         float ratio = (float) (dx1 *1.0 / dx);
         if (ratio <= 0.3){ //当高度比例小于0.3,所在比较高的时候就不进行绘制影子
             return ;
         }
         int ovalRadius = (int) (radius * ratio * density);
         //设置倒影的颜色
         mPaint.setColor(Color.parseColor( "#3F3B2D" ));
         //绘制椭圆
         rectF =  new  RectF(startX-ovalRadius,endY+10,startX+ovalRadius,endY+15);
         canvas.drawOval(rectF,mPaint);
     }
 
     /**
      * 设置颜色
      * @param color
      */
     public void setColor(int color) {
         this .color = color;
     }
     }

至此,全部的开发工作已经完成,基本功能已经实现,客官,你看懂了没有?

源码下载

github地址 
作者:mr_dsw 欢迎转载,与人分享是进步的源泉!

转载请保留地址:http://blog.csdn.net/mr_dsw

安装说明:解压至网站根目录即可 一如既往纯净 完整 无错 一比一完美精仿 界面完美 完全免费 上传即可使用 轻松建站 访问速度快 尝试原汁原味的sogou导航吗 喜欢的朋友赶快下吧 绿色源码 容量小 轻巧 傻瓜式免安装 简单 特别适合新手 轻松建站 支持自动获取北京时间 日期 农历 支持自动获取所在地城市天气预报 支持常用邮箱登陆 支持换肤 sogou导航界面特色:经典蓝色 版面整洁 排序有条 网址导航宗旨是方便网友们快速找到自已需要的网站 而不用去记太多复杂的网址 同时也提供了实用查询 邮箱快速登陆 天气预报等服务 我们的目标是通过网址导航使您上网更轻松 生活更便捷 在此 我们非常感谢一直喜欢和支持本站的网友们 2012 3 22 首版发布; 2012 8 4 修正搜索引擎切换出错问题; 2012 12 30 修正部份失效网址错误; 2013 7 4 修复内页搜索框BUG; 2014 1 24 更新2 1版本 全新2014版本 修改提示:  ※ 将网站域名地址替换成你的域名  ※ 将[网址导航]名称替换成你的网站名称  ※ 首页和内页LOGO在images v32目录; 请自行更改  ※ 统计代码在jsn tj js修改;  ※ 留言板管理后台http: 你的网站 feedback admin index asp 用户名:admin 密码:admin (登陆后台可修改密码) 上传即可使用 下载地址:http: www yx45 com cn">安装说明:解压至网站根目录即可 一如既往纯净 完整 无错 一比一完美精仿 界面完美 完全免费 上传即可使用 轻松建站 访问速度快 尝试原汁原味的sogou导航吗 喜欢的朋友赶快下吧 绿色源码 [更多]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值