Windows风格的Loading动画Android实现(1)
2015-07-13 10:00
405 查看
效果
前言
还不够完善,只做学习之用。原理
不停的重绘,即不停的改变点的位置以及透明度,不停的invaldate。所以,关键就在于根据动画执行时间确定点的位置以及透明度。首先定义,一个点飞入飞出所用时间为duration,点的数量为pointNum,那么可知pointNum*duration*2为一个周期。我们把动画执行时间对周期取余,自然就可得到循环重复效果。
在一个周期里面划分为pointNum*2步,前pointNum步是各个点依次飞入,后pointNum步是各个点依次飞出。根据动画当前执行到哪一步去计算点的位置。
把点的位置又分为三个部分——enterX, transX, exitX,分别代表飞入距离、平移距离、飞出距离。根据动画当前执行到哪一步分别计算。在计算飞入距离和飞出距离时利用补差器去让运动更加平滑。
源码
[code]package com.example.myronlg.windowsstyleloadingdemo; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; import android.view.View; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * Created by myron.lg on 2015/7/9. */ public class LoadingView extends View { /** * A list that contains the cx of each point. */ private List<Float> cx; /** * The cy of every point is the same. */ private float cy; /** * The radius of every point is the same. */ private float radius; /** * The paints that used to draw each point. */ private List<Paint> paints; /** * The length that point transfer to enter and exit. */ private float dx; private List<Float> dxs; /** * The offset between each point. */ private float offset; /** * Used in animation. */ private long startMillis = -1; /** * Used to make translation more smooth */ private Interpolator enterInterpolator, exitInterpolator; /** * The time one point enter or exit */ private long duration; /** * The moving velocity of the point which is not entering or exiting */ private float v = 0.04F; /** * The number of points */ private int pointNum; private float cxOffest; public LoadingView(Context context) { super(context); init(); } public LoadingView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public LoadingView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init(){ pointNum = 4; cx = new ArrayList<>(Collections.nCopies(pointNum, 0.0F)); Paint paint = new Paint(); paint.setDither(true); paint.setAntiAlias(true); paint.setColor(Color.parseColor("#00BCD4")); paint.setAlpha(0); paints = new ArrayList<>(); for (int i = 0; i < pointNum; i++) { paints.add(new Paint(paint)); } enterInterpolator = new DecelerateInterpolator(1.5F); exitInterpolator = new AccelerateInterpolator(2.0F); duration = 600; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); initSize(); } private void initSize(){ cy = getMeasuredHeight() / 2; radius = getMeasuredHeight() / 3; dx = getMeasuredWidth() / 3; cxOffest = (getMeasuredWidth() - 2*dx - v*duration*3) * 0.5F; offset = radius * 3; } @Override protected void onDraw(Canvas canvas) { for (int i = 0; i < cx.size(); i++) { canvas.drawCircle(cx.get(i), cy, radius, paints.get(i)); } update(); } private void update(){ long currentMillis = System.currentTimeMillis(); if (startMillis == -1){ startMillis = currentMillis; } // (pointNum * 2 * duration) is a cycle long passMills = (currentMillis - startMillis) % (pointNum * 2 * duration); // update each point's cx and alpha for (int i = 0; i < cx.size(); i++) { long step = passMills / duration; float animationFraction = (passMills % duration) * 1.0F / duration; float enterX = 0; float transX = 0; float exitX = 0; if (step < 4) { // entering half if (i < step) { enterX = dx - i*offset + i*duration*v; transX = (passMills - (i + 1) * duration) * v; exitX = 0; paints.get(i).setAlpha(255); } else if (i == step) { float interpolatedFraction = enterInterpolator.getInterpolation(animationFraction); enterX = interpolatedFraction*dx - i*offset + i*duration*v; transX = 0; exitX = 0; paints.get(i).setAlpha((int) (255*interpolatedFraction)); } else { enterX = 0; transX = 0; exitX =0; paints.get(i).setAlpha(0); } } else { // exiting half if (i < step-4){ enterX = dx - i*offset + i*duration*v; transX = (passMills - (i + 1) * duration) * v; exitX = dx; paints.get(i).setAlpha(0); } else if (i == step-4){ float interpolatedFraction = exitInterpolator.getInterpolation(animationFraction); enterX = dx - i*offset + i*duration*v; transX = (passMills - (i + 1) * duration) * v; exitX = interpolatedFraction * dx; paints.get(i).setAlpha((int) (255*(1-interpolatedFraction))); } else { enterX = dx - i*offset + i*duration*v; transX = (passMills - (i + 1) * duration) * v; exitX = 0; paints.get(i).setAlpha(255); } } cx.set(i, cxOffest + enterX + transX + exitX); } invalidate(); } }
相关文章推荐
- Android线程的创建与销毁
- android 动画效果
- 一些android错误
- 使用Android studio中遇到的各种问题记录
- Android(java)学习笔记124:Android权限大全
- 彻底解决Android SDK Manager更新慢的问题
- Android中友盟统计,用户反馈,在线升级配置概述
- Android特效 五种Toast详解
- Android调用JNI方法 及 代码
- 六款值得推荐的android(安卓)开源框架简介
- Android--如何使用API
- Android 事件处理全面剖析
- Android Studio 新手常见错误:Gradle DSL method not found: 'runProguard()'
- Android 开发有哪些新技术出现?
- 一些Android开发的博客收藏
- Android 开发工具下载
- Android开发工程师必备知识点(参考)
- 3.Android Studio 之命令行开发安卓
- 高德地图Android自定义路线规划的简单实现
- Android依赖注入: Dagger (Part 1)