Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android自定義View—仿雷達掃描效果

Android自定義View—仿雷達掃描效果

編輯:關於Android編程

最近在翻以前寫的代碼,翻到幾個月以前做的一個仿雷達掃描的效果,現在拿出來和大家分享一下,在進入分析和代碼之前,我們先來看看效果吧,

title=

…錄屏質量較差,湊活著看吧。看到這樣的效果,肯定是用自定義view的方式去實現的。通過觀察效果,我們先來列一列要用的知識吧。

整個過程是一個不斷繪制的過程,所以我們需要一個Handler。 核心的效果是一個扇形,所以我們還需要會繪制扇形。 繪制的扇形的顏色有一個梯度變化的效果,所以我們需要知道Shader的使用。 整個過程中扇形是不斷變化位置的,我們還需要知道如何去旋轉canvas。

ok,知道了這些,我們就一一來看一下上面的知識點。

一. 首先這個不斷繪制的過程,我們說用handler去實現,其實方式很多,只不過我個人比較喜歡用handler的方式去實現,至於怎麼使用,思路就是在Handler的handleMessage方法中繼續send一個message。
例如下面代碼:

private Handler mHandler = new Handler() {
        public void handleMessage(Message msg) {
            if(msg.what == MSG_RUN) {
                ...
                postInvalidate();
                sendEmptyMessage(MSG_RUN);
            }
        }
    };

二. 繪制扇形,如何利用canvas去繪制扇形,這都是最基本的知識了,這裡僅僅提一下就ok啦,

canvas.drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)

簡單說一下參數吧,第一個參數是指的這個扇形所在圓的一個外接矩形。

第二個參數是扇形開始的位置,這裡需要注意的是這個開始的位置是從坐標系的正東方向開始算起的。
如圖,

title=

第三個參數,指的是扇形的角度。

第四個參數如果設置false,繪制的是一段圓弧,true的話,繪制的才是一個實體的扇形。

三. Android提供了不少的Shader,我們這裡需要一個梯度的變化,這就需要SweepGradient這個類了。
來看看這個類的構造方法,

public SweepGradient (float cx, float cy, int color0, int color1)

這裡只看一個它的一個構造方法,前兩個參數是指梯度的圓心位置,後兩個參數指的是梯度開始的顏色和結束的顏色。

四. 旋轉canvas很容易,只需要調用canvas.rotate方法就ok,但是要記住在旋轉之前要保存現場,完畢之後要恢復現場。

除此之外,我們還需要繪制兩個圓和兩條線。

梳理完這些之後,下面我們正式開始編寫代碼實現這個效果了。
首先,我們先來初始化一些東西,

public class MyView extends View {

    private static final int MSG_RUN = 1;

    private Paint mCirclePaint; // 繪制圓形
    private Paint mArcPaint; // 繪制扇形
    private Paint mLinePaint; // 繪制線條

    private RectF mRectF;

    private int mSweep; // 扇形角度

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);

        mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mArcPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

        mCirclePaint.setColor(Color.BLACK);
        mCirclePaint.setStyle(Style.STROKE);
        mCirclePaint.setStrokeWidth(1.f);

        mArcPaint.setColor(Color.GRAY);
        mArcPaint.setStyle(Style.FILL);

        mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mLinePaint.setColor(Color.BLACK);
        mLinePaint.setStrokeWidth(1.f);

        mRectF = new RectF();
    }
}

這裡定義了3個Paint,分別用來繪制圓形、線條和扇形,並且在構造中初始化這些Paint。

因為我們需要的是一個正方形的區域,所以我們還需要重寫onMeasure方法,並且在這裡面設置Rect的值。

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    int size = getMeasuredWidth();
    setMeasuredDimension(size, size);
    mRectF.set(0, 0, getMeasuredWidth(), getMeasuredHeight());

    mArcPaint.setShader(new SweepGradient(size/2, size/2, Color.GRAY, Color.BLACK));
}

這裡我們設置我們的view大小是一個正方形,而且初始化了mRectF,這個我們在繪制的時候要用到。
最後,我們給繪制扇形的Paint設置了一個shader,這裡正是使用了SweepGradient,關於它的構造方法的在上面已經說明了。
繼續代碼,就到了繪制的時候了,怎麼繪制呢? 我們先來看代碼,

@Override
protected void onDraw(Canvas canvas) {
    int centerX = getMeasuredWidth() / 2;
    int centerY = getMeasuredHeight() / 2;

    canvas.save();
    canvas.rotate(mSweep, centerX, centerY);
    canvas.drawArc(mRectF, 0, mSweep, true, mArcPaint);
    canvas.restore();

    canvas.drawLine(0, centerY, getMeasuredWidth(), centerY, mLinePaint);
    canvas.drawLine(centerX, 0, centerX, getMeasuredHeight(), mLinePaint);

    canvas.drawCircle(centerX, centerY, centerX / 2, mCirclePaint);
    canvas.drawCircle(centerX, centerY, centerX, mCirclePaint);
}

這裡分為三個部分,後兩個部分很容易,就是繪制了兩條橫豎的線條和兩個大小不一樣的圓。最重要的還是看第一部分,首先我們保存現場,因為我們在這裡要去旋轉畫布。接下來果然是去旋轉了畫布,旋轉的角度是mSweep,這個值在後面我們會不斷的去改變它,最後使用drawArc方法去繪制出了我們需要的扇形,可以看到這裡的繪制的開始位置一直是0,那我們在效果圖中看到的開始位置不斷變化是怎麼回事?答案正式我們旋轉了畫布角度的結果!最後的最後,別忘了去恢復現場。

現在整個繪制的流程就走完了,也可見看到這樣一個效果是如此的簡單,接下來就是如何開始這個動畫,並且不斷的去繪制。

public void start() {
    mHandler.sendEmptyMessage(MSG_RUN);
}

private Handler mHandler = new Handler() {
    public void handleMessage(Message msg) {
        if(msg.what == MSG_RUN) {
            mSweep+=2;
            if(mSweep > 360) mSweep = 0;
            postInvalidate();
            sendEmptyMessage(MSG_RUN);
        }
    }
};

我們公開了一個start方法用來開啟動畫,在start中是調用了handler的sendEmptyMessage去發送一個效果,接下來我們來看看handler中的邏輯。在handler的handleMessage中,我們去改變mSweep的值,如果他的值大於360度,則重新置0,最後再次發送出一個效果,這樣就達到了一個不斷改變mSweep的值的目的,而且它的值是在0~360度之間。

ok,到現在這個簡單的效果就完成了,我們只需要在xml布局中使用這個view,然後在activity中調用它的start方法,就可以顯示出這個絢麗的效果了。

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved