Android自定義View之仿金山詞霸加載效果

今天,閒來無事,看到金山詞霸的加載時的LoadingView甚是不錯,於是就小模仿了一下。先看效果:這裏寫圖片描述
下面切入正題,先說下思路:
1.確定中心點的座標
2.根據正餘弦函數,確定8個小圓的圓心座標
3.定義有8個顏色的數組,畫圓的時候依次用不用顏色的畫筆

注意:畫圓之前要把之前畫的圓的顏色置爲灰色
下面自定義View的代碼:
CircleLoading.java

public class CircleLoading extends View{

    private Paint mPaint;   //畫筆
    private Context mContext;   
    private float mRadius;  //小圓半徑
    private int radius; //大圓半徑

    private float centerX;
    private float centerY;
    private int currentPosition = 6;    //動畫起始位置(即動畫從最靠上的那個圓開始)
    private boolean isStart = false;
    //定義8種顏色
    private int colors[] = {Color.YELLOW,Color.GREEN,Color.CYAN,
            Color.BLUE,Color.parseColor("#9809F7"),
            Color.parseColor("#03F0F7"),Color.RED,
            Color.parseColor("#F85004")};

    public CircleLoading(Context context) {
        this(context,null);
    }

    public CircleLoading(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public CircleLoading(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context) {
        mContext = context;
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Style.FILL);
        mPaint.setColor(Color.GRAY);
        radius = dip2px(30);
        mRadius = dip2px(5);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);

        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);

        //處理 wrap_content問題
        int defaultDimension = dip2px(100);
        if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(defaultDimension, defaultDimension);
        } else if (widthSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(defaultDimension, heightSpecSize);
        } else if (heightSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(widthSpecSize, defaultDimension);
        }

    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        centerX = w/2;
        centerY = h/2;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint.setColor(Color.GRAY);
        for(int i = 0;i<8;i++){
            float circleX = (float) (centerX + radius * Math.cos(Math.PI * i / 4));
            float circleY = (float) (centerY + radius * Math.sin(Math.PI *i/4));
            canvas.drawCircle(circleX, circleY, mRadius, mPaint);
        }
        if(isStart){
            mPaint.setColor(colors[currentPosition]);
            float cx = (float) (centerX + radius * Math.cos(Math.PI * currentPosition / 4));
            float cy = (float) (centerY + radius * Math.sin(Math.PI * currentPosition/4));
            canvas.drawCircle(cx, cy, mRadius, mPaint);
        }
    }

    //開始動畫
    public void startAnimator() {
        isStart = true;
        new Thread(new Runnable() {

            @Override
            public void run() {
                while(true){
                    Log.i("Main", "currentPosition:"+currentPosition);
                    postInvalidate();
                    currentPosition++;
                    if(currentPosition == 8){
                        currentPosition = 0;
                    }
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

            }
        }).start();
    }

    //停止動畫
    public void stopAnimator() {
        isStart = false;
        postInvalidate();
    }

    /**
     * 根據手機的分辨率從 dp 的單位 轉成爲 px(像素)
     */
    public int dip2px(float dpValue) {
        final float scale = mContext.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

}

接下來是xml文件:
activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">


    <com.sky.view.CircleLoading 
        android:id="@+id/circle_load"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"/>


</RelativeLayout>

最後是我們的MainActivity:
MainActivity.java

public class MainActivity extends Activity{

    private CircleLoading circleLoading;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        circleLoading = (CircleLoading) findViewById(R.id.circle_load);
        circleLoading.startAnimator();
    }

}

有關自定義View的知識還是非常多的,這些還都是一些皮毛,有機會深入研究,繼續更新。。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章