用过android 搜狗浏览器客户端的用户就知道,每次加载页面就会有个下落的加载小球,为了实现它,我上网查资料,在泡在网上的日子上面找到了相关资料,但是没有具体详细的教程,所以我就分享一下我的思路。
先上一张效果图(由于博主一直没有找到怎么在博客中播放gif,所以就来一张静态的吧,要想看具体效果,清下载源码编译):
具体思路:
1、继承View自写控件,并获取控件长宽。
2、根据已经获取的长宽,设置小球下落的距离。
3、确定小球开始变形的临界点,小球下落至此就开始画椭圆和小球影子。
4、用ValueAnimator控制小球下落的速度和获取小球的下落位置,并且随时更新小球。
运动过程图形解说:
主要实现代码:
package com.tielizi.loaderanimation;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import java.util.Random;
/**
* Created by Administrator on 2015/10/12.
*/
public class LoaderView extends View {
private int radious;//半径
private float ratio;//下降比例
private Paint shadowPaint,circlePaint;//画下落的影子和小球的画笔
private float endX,startY,endY,currentDropDistance,dropDistance,changedistance,currentY = 0;
private RectF rectF;
private boolean flag;//标记标记线程是否结束
private String [] color = new String[]{"#9966FF","#FF6600","#FF00FF","#66FF33","#FF0000"};
public LoaderView(Context context) {
super(context);
init();
}
public LoaderView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public LoaderView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
// public LoaderView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
// super(context, attrs, defStyleAttr, defStyleRes);
// init();
// }
private void init(){
flag = true;
circlePaint = new Paint();
circlePaint.setStyle(Paint.Style.FILL);
circlePaint.setAntiAlias(true);
shadowPaint = new Paint();
shadowPaint.setColor(Color.GRAY);
shadowPaint.setStyle(Paint.Style.FILL);
shadowPaint.setAntiAlias(true);
new Thread(new Runnable() {//线程改变画笔颜色
@Override
public void run() {
while(flag){
circlePaint.setColor(Color.parseColor(color[(new Random()).nextInt(color.length)]));
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
@Override
protected void onDraw(Canvas canvas) {
Log.i("px","Draw!");
if(currentY == 0){
executeValueAnimatior();
}else{
currentDropDistance = currentY-startY;
changedistance = dropDistance*3/4;
ratio = (currentDropDistance - changedistance)/(dropDistance/4)/2;
drawDropCircle(canvas);
}
super.onDraw(canvas);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Log.i("px","Ready!");
radious = getWidth()/20;
endX = getWidth()/2;
endY = getHeight()*2/3;
startY = endY*2/3;
dropDistance = endY/3;
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
private void drawDropCircle(Canvas canvas){//话下落的小球
if(currentDropDistance<changedistance){
canvas.drawCircle(endX,currentY,radious,circlePaint);
}else{
drawShadow(canvas);
rectF = new RectF(endX-radious*(1+ratio),currentY-radious,endX+radious*(1+ratio),currentY+radious*(1-ratio));
canvas.drawOval(rectF,circlePaint);
}
}
private void drawShadow(Canvas canvas){//画影子
rectF = new RectF(endX-radious*(1+ratio)/2,endY+radious/4,endX+radious*(1+ratio)/2,endY+radious/2+radious/10);
canvas.drawOval(rectF,shadowPaint);
// canvas.drawCircle(endX,endY+radious,radious*ratio,paint);
}
private void executeValueAnimatior(){//下落的小球位置的动画参数变化
ValueAnimator valueAnimator = ValueAnimator.ofInt((int)startY,(int)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();
}
public void setFlag(boolean b){//设置为线程结束
flag = b;
Log.i("px","结束线程!");
}
}
好了。就是这么简单。
相关博客:
时钟加载View
更多教程请访问博主博客。有什么问题可以私信博主。