文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2022-06-06 08:10

关注

一直都在看自定义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);
 }

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


 
 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);
 }

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



 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);
 }

第三个:



 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);
 }

第四个:


 
 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);
 }
 }
 
 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);
 }
 
 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);
 }
 
 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);
 }
 
 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);
 }
}
您可能感兴趣的文章:利用Android中的TextView实现逐字显示动画Android属性动画实现布局的下拉展开效果Android实现左右摆动的球体动画效果


阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯