模仿搜狗浏览器加载小球

用过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

更多教程请访问博主博客。有什么问题可以私信博主。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值