Android仿ViVO X6 极速闪充动画效果

一直都在看自定义View,经过一个星期的坚持,基本上能够写出一些比较实用的控件效果了,今天天气太热,就待在家里玩手机,然后手机没电了,在充电的时候,看到了手机的充电动画,觉得挺酷,然后自己我就仔细的分析了一下这里的动画内容,就觉得,这个我也能写出来,所以就有了这篇博客。纯属原创。

先看看效果,因为图片的原因,只能看到静态的。

这个就是效果图了。当然了,这么看好像不怎么样,但是配上了动画,还是挺好看的。

自定义控件的话,其实做的多了,运用的多了,就会觉得自定义View,跟在Photo shop 里面画图一样,我们通过建立图层,然后再图层里面绘制自己想要的效果。

这里其实也是一样的,运用到了我前面讲的一些知识,比如这篇:
Android自定义View弧线进度控件,原理上大体相当,结合这次的效果,我们看看,这里面是有四个弧形,两个圆,还有一个类似于时钟刻度的效果。所以知道这些的话,这就比较容易实现了。

首先,新建一个类,取名为VIVOPhone,然后继承自View,重载三个构造函数,然后进入主题。

同样的,我们先看看运用到了哪些变量

 // 定义五个画笔
 private Paint mSmileRing, mBigRing, mInCrilePaint, mInLine, mTextPaint;
 // 控件的高宽
 private float mWidth, mHeight;
 // 矩形的空间
 private RectF mRectF;
 // 四个弧线的开始角度
 private float startAngle = 270, startAngle2 = 270, startAngle3 = 270,
  startAngle4 = 270, sweepAngle = 90;
 // 文字
 private String text = "70%";
 // 文字的大小
 private float tvSize = 80;
 // 刻度的进度
 private float progress;

然后我们开始初始化数据。

private void initView() {
 mSmileRing = new Paint();
 mSmileRing.setAntiAlias(true);
 mSmileRing.setStrokeWidth(5);
 mSmileRing.setStyle(Style.STROKE);
 mSmileRing.setColor(Color.parseColor("#12ADFF"));

 mBigRing = new Paint();
 mBigRing.setAntiAlias(true);
 mBigRing.setStrokeWidth(20);
 mBigRing.setStyle(Style.STROKE);
 mBigRing.setColor(Color.parseColor("#12ADFF"));

 mInCrilePaint = new Paint();
 mInCrilePaint.setAntiAlias(true);
 mInCrilePaint.setStrokeWidth((float) 0.5);
 mInCrilePaint.setStyle(Style.STROKE);
 mInCrilePaint.setColor(Color.parseColor("#eeeeee"));

 mInLine = new Paint();
 mInLine.setAntiAlias(true);
 mInLine.setStrokeWidth(3);
 mInLine.setColor(Color.parseColor("#00ff00"));

 mTextPaint = new Paint();
 mTextPaint.setAntiAlias(true);
 mTextPaint.setStrokeWidth(3);
 mTextPaint.setTextSize(tvSize);
 mTextPaint.setColor(Color.parseColor("#ffffff"));
 }

这里主要是对画笔进行初始化,包括设置大小、宽度、样式、颜色等等。这个方法,最后还是要在构造函数里面调用。

画笔初始化好了,接下来就看看怎么给变量赋值;

一样的,我们还是在onSizeChange()方法里面写赋值的操作。代码如下:

 @Override
 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
 super.onSizeChanged(w, h, oldw, oldh);
 mWidth = w;
 mHeight = h;

 }

这里很简单,就是给高跟宽赋值。

好了,最后看看onDraw方法是怎么写的。

 @Override
 protected void onDraw(Canvas canvas) {
 super.onDraw(canvas);
 canvasOutArc1(canvas, mRectF);
 canvasOutArc2(canvas, mRectF);
 canvasOutArc3(canvas, mRectF);
 canvasOutArc4(canvas, mRectF);
 drawCircle(canvas);
 drawCircleIn(canvas);
 canvasDrawText(canvas);

 }

没错,我这里把每一个的绘制都抽成了方法,这样是为了更好的管理和阅读。看到一个:

 /**
 * 绘制最外面的弧线
 *
 * @param canvas
 */
 private void canvasOutArc1(Canvas canvas, RectF mRectF) {
 mRectF = new RectF((float) (mWidth * 0.1), (float) (mWidth * 0.1),
  (float) (mWidth * 0.9), (float) (mWidth * 0.9));
 canvas.drawArc(mRectF, startAngle, sweepAngle + 90, false, mSmileRing);
 }

这个是最外层的圆,接下来就是第二个,第三个,第四个,我全部列出来。

/**
 * 绘制外层的第二个
 *
 * @param canvas
 * @param mRectF
 */
 private void canvasOutArc2(Canvas canvas, RectF mRectF) {
 mRectF = new RectF((float) (mWidth * 0.14), (float) (mWidth * 0.14),
  (float) (mWidth * 0.85), (float) (mWidth * 0.85));
 canvas.drawArc(mRectF, startAngle2, sweepAngle + 30, false, mBigRing);
 }

第三个:

/**
 * 绘制里面第二个小的
 *
 * @param canvas
 */
 private void canvasOutArc3(Canvas canvas, RectF mRectF) {
 mRectF = new RectF((float) (mWidth * 0.22), (float) (mWidth * 0.22),
  (float) (mWidth * 0.795), (float) (mWidth * 0.795));
 canvas.drawArc(mRectF, startAngle3, sweepAngle, false, mSmileRing);
 }

第四个:

 /**
 * 绘制里面第二个小的
 *
 * @param canvas
 */
 private void canvasOutArc4(Canvas canvas, RectF mRectF) {
 mRectF = new RectF((float) (mWidth * 0.255), (float) (mWidth * 0.255),
  (float) (mWidth * 0.75), (float) (mWidth * 0.75));
 canvas.drawArc(mRectF, startAngle4, sweepAngle, false, mBigRing);
 }

然后就是两个圆了:

第一个圆,这里面还包含了锯齿:

// 绘制内切圆和锯齿
 private void drawCircle(Canvas canvas) {
 float radius = (float) (mHeight - (mHeight * 0.3) * 2 - (mWidth * 0.17));
 float yuanX = (float) (mHeight / 2);
 float yuanY = (float) (mWidth / 2);

 canvas.drawCircle(yuanX, yuanY, radius, mInCrilePaint);
 canvas.save();

 float nowWidth = (float) (getMeasuredWidth());
 float nowHeight = getMeasuredHeight();
 for (int i = 0; i < 72; i++) {
  // canvas.drawLine(nowWidth / 2, nowHeight / 2 - nowWidth / 2,
  // nowWidth / 2, nowHeight / 2 - nowWidth / 2 + 30, mInLine);

  if (i >= progress) {
  mInLine.setColor(Color.parseColor("#555555"));
  } else {
  mInLine.setColor(Color.parseColor("#00ff00"));
  }

  canvas.drawLine(nowWidth / 2,
   (float) (nowHeight / 2 - nowWidth / 2 + mWidth / 3.7),
   nowWidth / 2, (float) (nowHeight / 2 - nowWidth / 2
    + mWidth * 0.05 + mWidth / 3.7), mInLine);

  canvas.rotate(5, getWidth() / 2, getHeight() / 2);

 }

 }

第二个圆:

// 绘制最里面的圆
 private void drawCircleIn(Canvas canvas) {
 float radius = (float) (mHeight - (mHeight * 0.3) * 2 - (mWidth * 0.22));
 float yuanX = (float) (mHeight / 2);
 float yuanY = (float) (mWidth / 2);

 canvas.drawCircle(yuanX, yuanY, radius, mInCrilePaint);
 canvas.save();

 }

最后暴露给外面一个方法,用于动画效果:

 public void setData(int startAngle, float d) {
 this.startAngle = startAngle;
 this.startAngle2 = 360 - startAngle;
 this.startAngle3 = startAngle;
 this.startAngle4 = 360 - startAngle;
 progress = d / 4;
 postInvalidateDelayed(500);
 }

这里为了效果更明显,我让它五毫秒的速度更新UI,这里就是View的全部内容,下面,我把所有的代码都列出来:

布局文件:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:background="@drawable/bg"
 tools:context=".MainActivity" >

 <com.example.vivoopen.weight.VivoView
 android:id="@+id/vivo"
 android:layout_width="180dip"
 android:layout_height="180dip"
 android:layout_centerInParent="true" />

</RelativeLayout>

MainActivity.java:

public class MainActivity extends Activity {
 private VivoView view;
 private boolean isRun = true;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 view = (VivoView) findViewById(R.id.vivo);

 new Thread(new Runnable() {
  public void run() {
  synchronized (view) {

   while (isRun) {
   Message msg;
   for (int i = 0; i < n2; i = i + 10) {
    msg = new Message();
    msg.obj = i;
    SystemClock.sleep(100);
    msg.what = 1;
    handler.sendMessage(msg);
   }
   msg = new Message();
   msg.what = 2;
   handler.sendMessage(msg);
   }
  }
  }
 }).start();

 }

 int n2 = 2;
 private Handler handler = new Handler() {
 public void handleMessage(android.os.Message msg) {

  switch (msg.what) {
  case 1:
  int a = (Integer) msg.obj;
  view.setData(a, a);
  break;
  case 2:
  n2 = 359;
  break;
  default:
  break;
  }

 };
 };

}

VivoView.java:

public class VivoView extends View {
 // 定义五个画笔
 private Paint mSmileRing, mBigRing, mInCrilePaint, mInLine, mTextPaint;
 // 控件的高宽
 private float mWidth, mHeight;
 // 矩形的空间
 private RectF mRectF;
 // 四个弧线的开始角度
 private float startAngle = 270, startAngle2 = 270, startAngle3 = 270,
  startAngle4 = 270, sweepAngle = 90;
 // 文字
 private String text = "70%";
 // 文字的大小
 private float tvSize = 80;
 // 刻度的进度
 private float progress;

 public VivoView(Context context, AttributeSet attrs, int defStyle) {
 super(context, attrs, defStyle);
 initView();

 }

 public VivoView(Context context, AttributeSet attrs) {
 super(context, attrs);
 initView();
 }

 public VivoView(Context context) {
 super(context);
 initView();
 }

 private void initView() {
 mSmileRing = new Paint();
 mSmileRing.setAntiAlias(true);
 mSmileRing.setStrokeWidth(5);
 mSmileRing.setStyle(Style.STROKE);
 mSmileRing.setColor(Color.parseColor("#12ADFF"));

 mBigRing = new Paint();
 mBigRing.setAntiAlias(true);
 mBigRing.setStrokeWidth(20);
 mBigRing.setStyle(Style.STROKE);
 mBigRing.setColor(Color.parseColor("#12ADFF"));

 mInCrilePaint = new Paint();
 mInCrilePaint.setAntiAlias(true);
 mInCrilePaint.setStrokeWidth((float) 0.5);
 mInCrilePaint.setStyle(Style.STROKE);
 mInCrilePaint.setColor(Color.parseColor("#eeeeee"));

 mInLine = new Paint();
 mInLine.setAntiAlias(true);
 mInLine.setStrokeWidth(3);
 mInLine.setColor(Color.parseColor("#00ff00"));

 mTextPaint = new Paint();
 mTextPaint.setAntiAlias(true);
 mTextPaint.setStrokeWidth(3);
 mTextPaint.setTextSize(tvSize);
 mTextPaint.setColor(Color.parseColor("#ffffff"));
 }

 @Override
 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
 super.onSizeChanged(w, h, oldw, oldh);
 mWidth = w;
 mHeight = h;

 }

 @Override
 protected void onDraw(Canvas canvas) {
 super.onDraw(canvas);
 canvasOutArc1(canvas, mRectF);
 canvasOutArc2(canvas, mRectF);
 canvasOutArc3(canvas, mRectF);
 canvasOutArc4(canvas, mRectF);
 drawCircle(canvas);
 drawCircleIn(canvas);
 canvasDrawText(canvas);

 }

 // 绘制文字
 private void canvasDrawText(Canvas canvas) {
 float textSize = mTextPaint.measureText(text);
 float x = mWidth / 2 - textSize / 2;
 float y = mHeight / 2 + textSize / 5;
 canvas.drawText(text, x, y, mTextPaint);
 }

 // 绘制最里面的圆
 // 绘制内切圆和锯齿
 private void drawCircleIn(Canvas canvas) {
 float radius = (float) (mHeight - (mHeight * 0.3) * 2 - (mWidth * 0.22));
 float yuanX = (float) (mHeight / 2);
 float yuanY = (float) (mWidth / 2);

 canvas.drawCircle(yuanX, yuanY, radius, mInCrilePaint);
 canvas.save();

 }

 // 绘制内切圆和锯齿
 private void drawCircle(Canvas canvas) {
 float radius = (float) (mHeight - (mHeight * 0.3) * 2 - (mWidth * 0.17));
 float yuanX = (float) (mHeight / 2);
 float yuanY = (float) (mWidth / 2);

 canvas.drawCircle(yuanX, yuanY, radius, mInCrilePaint);
 canvas.save();

 float nowWidth = (float) (getMeasuredWidth());
 float nowHeight = getMeasuredHeight();
 for (int i = 0; i < 72; i++) {
  // canvas.drawLine(nowWidth / 2, nowHeight / 2 - nowWidth / 2,
  // nowWidth / 2, nowHeight / 2 - nowWidth / 2 + 30, mInLine);

  if (i >= progress) {
  mInLine.setColor(Color.parseColor("#555555"));
  } else {
  mInLine.setColor(Color.parseColor("#00ff00"));
  }

  canvas.drawLine(nowWidth / 2,
   (float) (nowHeight / 2 - nowWidth / 2 + mWidth / 3.7),
   nowWidth / 2, (float) (nowHeight / 2 - nowWidth / 2
    + mWidth * 0.05 + mWidth / 3.7), mInLine);

  canvas.rotate(5, getWidth() / 2, getHeight() / 2);

 }

 }

 /**
 * 绘制最外面的弧线
 *
 * @param canvas
 */
 private void canvasOutArc1(Canvas canvas, RectF mRectF) {
 mRectF = new RectF((float) (mWidth * 0.1), (float) (mWidth * 0.1),
  (float) (mWidth * 0.9), (float) (mWidth * 0.9));
 canvas.drawArc(mRectF, startAngle, sweepAngle + 90, false, mSmileRing);
 }

 /**
 * 绘制外层的第二个
 *
 * @param canvas
 * @param mRectF
 */
 private void canvasOutArc2(Canvas canvas, RectF mRectF) {
 mRectF = new RectF((float) (mWidth * 0.14), (float) (mWidth * 0.14),
  (float) (mWidth * 0.85), (float) (mWidth * 0.85));
 canvas.drawArc(mRectF, startAngle2, sweepAngle + 30, false, mBigRing);
 }

 /**
 * 绘制里面第二个小的
 *
 * @param canvas
 */
 private void canvasOutArc3(Canvas canvas, RectF mRectF) {
 mRectF = new RectF((float) (mWidth * 0.22), (float) (mWidth * 0.22),
  (float) (mWidth * 0.795), (float) (mWidth * 0.795));
 canvas.drawArc(mRectF, startAngle3, sweepAngle, false, mSmileRing);
 }

 /**
 * 绘制里面第二个小的
 *
 * @param canvas
 */
 private void canvasOutArc4(Canvas canvas, RectF mRectF) {
 mRectF = new RectF((float) (mWidth * 0.255), (float) (mWidth * 0.255),
  (float) (mWidth * 0.75), (float) (mWidth * 0.75));
 canvas.drawArc(mRectF, startAngle4, sweepAngle, false, mBigRing);
 }

 public void setData(int startAngle, float d) {
 this.startAngle = startAngle;
 this.startAngle2 = 360 - startAngle;
 this.startAngle3 = startAngle;
 this.startAngle4 = 360 - startAngle;
 progress = d / 4;
 postInvalidateDelayed(500);
 }

}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android属性动画实现布局的下拉展开效果

    在Android的3.0之后,google又提出了属性动画的这样一个框架,他可以更好的帮助我们实现更丰富的动画效果.所以为了跟上技术的步伐,今天就聊一聊属性动画. 这一次的需求是这样的:当点击一个View的时候,显示下面隐藏的一个View,要实现这个功能,需要将V iew的visibility属性设置gone为visible即可,但是这个过程是一瞬间的,并不能实现我们要的效果.所以,属性动画是个不错的方案. 先把效果贴上 第一个:  第二个: 前面的这个是隐藏着,后面这个是显示的.当点击这个箭头

  • Android实现左右摆动的球体动画效果

    首先,看一下效果 可能各位在别处看到过类似的东西,我在微信的文章末尾看到有个玩意,感觉有意思,就用代码实现一下.这篇文章主要把握写代码的思路展示一下. 看到上图,我想各位能想到最简单的实现方案就是用动画,切很多图出来,然后就可以轻松实现了.为了不让自己再舒适区里呆的太安逸,就弄点麻烦的:通过计算来实现.文章的末尾会将全部代码贴出,复制可以直接运行. 需要回忆的知识 重力势能 E = mgh 动能 E = ½mv² 在理想状态下,动能和重力式能可以相互转换,且能量守恒 如果不想太注意细节,以上的知

  • 利用Android中的TextView实现逐字显示动画

    前言 Android的TextView只能设置整个TextView的动画,而不能设置每个文字的动画.即使是使用TextSwitcher,也很难实现我想要的效果. 所以选择自定义一个.大体思路是:继承ViewGroup,设置Text的时候,每个文字为一个TextView,每隔一个固定时间,启动每个TextView的动画. 定义一个CTextView,继承ViewGroup: 实现主要代码: public class CTextView extends ViewGroup { } 向外提供一个方法s

  • Android仿ViVO X6 极速闪充动画效果

    一直都在看自定义View,经过一个星期的坚持,基本上能够写出一些比较实用的控件效果了,今天天气太热,就待在家里玩手机,然后手机没电了,在充电的时候,看到了手机的充电动画,觉得挺酷,然后自己我就仔细的分析了一下这里的动画内容,就觉得,这个我也能写出来,所以就有了这篇博客.纯属原创. 先看看效果,因为图片的原因,只能看到静态的. 这个就是效果图了.当然了,这么看好像不怎么样,但是配上了动画,还是挺好看的. 自定义控件的话,其实做的多了,运用的多了,就会觉得自定义View,跟在Photo shop 里

  • Android仿支付宝中余额宝的数字动画效果

    实现效果图: 下面是具体代码,可直接复制: package com.lcw.rabbit.widget; import android.animation.ObjectAnimator; import android.content.Context; import android.text.TextUtils; import android.util.AttributeSet; import android.view.animation.AccelerateDecelerateInterpola

  • Android仿视频加载旋转小球动画效果的实例代码

    先上个效果图,以免大家跑错地了. 嗯,除了只能录三秒,其他没啥问题. 下面分析一下怎么实现上面这个效果. 理性分析后我们可以看到是几个小球绕着一个圆进行运动,那这里面的重点我们看看什么. 绘制五个球,没什么难度,让球绕圆进行运动,这个好像我们没有见到是怎么去实现了,那下就说这个. 从本质上看,球绕圆运动,其实我们可以看作是一个物体绕指定的路劲运动,那我们就有下面几个东西需要说一下: 1:Path 2:ValueAnimator 3:PathMeasure 前两个大家应该都见过,一个是路径,就是可

  • Android 自定View实现仿QQ运动步数圆弧及动画效果

    在之前的Android超精准计步器开发-Dylan计步中的首页用到了一个自定义控件,和QQ运动的界面有点类似,还有动画效果,下面就来讲一下这个View是如何绘制的. 1.先看效果图 2.效果图分析 功能说明:黄色的代表用户设置的总计划锻炼步数,红色的代表用户当前所走的步数. 初步分析:完全自定义View重写onDraw()方法,画圆弧. 3.画一个圆弧必备知识 在Canvas中有一个画圆弧的方法 drawArc(RectF oval, float startAngle, float sweepA

  • Android仿支付宝笑脸刷新加载动画的实现代码

    看到支付宝的下拉刷新有一个笑脸的动画,因此自己也动手实现一下.效果图如下: 一.总体思路 1.静态部分的笑脸. 这一部分的笑脸就是一个半圆弧,加上两颗眼睛,这部分比较简单,用于一开始的展示. 2.动态笑脸的实现. 2.1.先是从底部有一个圆形在运动,运动在左眼位置时把左眼给绘制,同时圆形继续运动,运动到右眼位置时绘制右眼,圆形继续运动到最右边的位置. 2.2.当上面的圆形运动到最右边时候,开始不断绘制脸,从右向左,脸不断增长,这里脸设置为接近半个圆形的大小. 2.3.当脸画完的时候,开始让脸旋转

  • android仿爱奇艺加载动画实例

    本篇文章介绍了android仿爱奇艺加载动画实例,具体代码如下: 效果图: 用到的知识点: Path ValueAnimator 如果对Path和ValueAnimator还不熟悉推荐去看这几个大神的Blog自定义view的目前讲的最适合我的文章 ,自定义view的详细教程和实践,这个也是教程和实践,感谢他们的付出!(希望大家可以认真看完,可以得到很多启发). 拆解动画 一个圆先顺时针的慢慢画出来(圆不是一个闭合的圆) 这一步是一个组合动画,圆慢慢的消失,同时三角形顺时针旋转 这里的难点主要就是

  • Android实现仿iOS菊花加载圈动画效果

    常见的实现方式 切图,做旋转动画 自定义View,绘制效果 gif图 1.切图会增加体积,但相对简单,不过在换肤的场景下,会使用不同颜色,需要准备多张图,不够灵活. 2.由于自定义的好处,不同颜色只需要提供自定义属性,换肤时切换属性设置即可,比较灵活. 3.gif图普遍比较大,而且加载gif没有原生支持,需要引入第三方库,而且消耗内存比较大,不推荐. 效果图: 完整代码 自定义属性: <?xml version="1.0" encoding="utf-8"?&

  • Android仿微信图片点击全屏效果

    废话不多说,先看下效果: 先是微信的 再是模仿的 先说下实现原理,再一步步分析 这里总共有2个Activity一个就是主页,一个就是显示我们图片效果的页面,参数通过Intent传送,素材内容均来自网络,(感谢聪明的蘑菇) 图片都是Glide异步下的,下的,下的重要的事情说三次,然后就是用动画做放大操作然后显示出来了(并没有做下载原图的实现,反正也是一样 下载下来Set上去而且动画都不需要更简便). OK,我们来看分析下 obj,目录下分别创建了2个对象,一个用来使用来处理显示页面的图片尺寸信息以

  • Android仿知乎悬浮功能按钮FloatingActionButton效果

    前段时间在看属性动画,恰巧这个按钮的效果可以用属性动画实现,所以就来实践实践.效果基本出来了,大家可以自己去完善. 首先看一下效果图: 我们看到点击FloatingActionButton后会展开一些item,然后会有一个蒙板效果,这都是这个View的功能.那么这整个View肯定是个ViewGroup,我们一部分一部分来看. 首先是这个最小的Tag: 这个Tag带文字,可以是一个TextView,但为了美观,我们使用CardView,CardView是一个FrameLayout,我们要让它具有显

  • Android仿百度外卖自定义下拉刷新效果

    现如今的APP各式各样,同样也带来了各种需求,一个下拉刷新都能玩出花样了,前两天订饭的时候不经意间看到了"百度外卖"的下拉刷新,今天的主题就是它–自定义下拉刷新动画. 看一下实现效果吧: 动画 我们先来看看Android中的动画吧: Android中的动画分为三种: Tween动画,这一类的动画提供了旋转.平移.缩放等效果. Alpha – 淡入淡出 Scale – 缩放效果 Roate – 旋转效果 Translate – 平移效果 Frame动画(帧动画),这一类动画可以创建一个D

随机推荐