Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android自定義UI實戰(基礎篇2)---搜索酷炫界面

Android自定義UI實戰(基礎篇2)---搜索酷炫界面

編輯:關於Android編程

在實現搜索功能的時候,比如藍牙搜索,附近熱點搜索等,通常我們需要一個比較友好的界面,以下通過自定義View來實現一個搜索界面。

效果圖如下:
這裡寫圖片描述

當實現一個這樣的動畫的時候,思路是這樣的呢?將整個View拆分,可以分為三個部分。

第一部分: 實現中間的圖片
第二部分: 實現擴散的圓
第三部分: 實現游標轉動

這樣一個酷炫的搜索效果就出來了,用到的資源文件主要有兩張圖片:

這裡寫圖片描述這裡寫圖片描述

首先自定義一個類繼承自View,實現對應的構造方法,添加自定義屬性。上篇有詳細的實現流程。
相關代碼如下:
定義兩張圖片的屬性



    
    

獲取屬性:

/**
 * 取得相關自定義屬性
 * @param context
 * @param attrs
 */
private void initAttrs(Context context,AttributeSet attrs){
    mContext = context;
    TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.SearchAnimation);
    drawableSearchCenter  = typedArray.getDrawable(R.styleable.SearchAnimation_drawable_search_center);
    drawableSearchCursor  = typedArray.getDrawable(R.styleable.SearchAnimation_drawable_search_cursor);
    typedArray.recycle();
}

1 繪制中心圖片

@Override
protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //首先來繪制中心的圖片
        dsCenterW = drawableSearchCenter.getIntrinsicWidth();          //獲取到中心圖片的寬高
        dsCenterH = drawableSearchCenter.getIntrinsicHeight();
        centerX = ViewSizeHelper.getDeviceWidth((Activity) mContext)/2; //獲取到屏幕的寬高
        centerY = ViewSizeHelper.getDeviceHeight((Activity) mContext)/2;

        drawableSearchCenter.setBounds(centerX- (dsCenterW/2),centerY- (dsCenterH/2), centerX+ (dsCenterW/2),centerY+(dsCenterH/2)); //指定Drawable的繪制區域
        drawableSearchCenter.draw(canvas); //繪制drawable到畫布上
}

中心圖片就簡單的實現了。

2 實現擴散圓

圓的動態變化,使用ValueAnimator來實現。通過改變圓的半徑,不斷的重繪就可以實現這種效果了,

canvas.save();  
canvas.drawCircle(centerX, centerY, radius, mPaint);
canvas.restore();

重點是實現radius的變化,這裡使用ValueAnimator,自定義Evalutor來實現(使用ofObject )
下面來看如何實現自定義的Evalutor
首先定義一個類

/**
 * Created by Mirko on 2016/11/9 20:47.
 */

public class SearchRadius {
    private int radius;

    public SearchRadius(int radius){
        this.radius = radius;
    }
    public int getRadius() {
        return radius;
    }
    public void setRadius(int radius) {
        this.radius = radius;
    }
}

創建自定義的Evalutor

/**
 * Created by Mirko on 2016/11/9 20:50.
 */

public class RadiusEvaluator implements TypeEvaluator {

    @Override
    public SearchRadius evaluate(float fraction, SearchRadius startValue, SearchRadius endValue) {
        int start = startValue.getRadius();
        int end  = endValue.getRadius();
        int curValue = (int)(start + fraction * (end - start));  //根據初始值和結束值計算出當前值。
        return new SearchRadius(curValue);
    }
}

完成上述步驟後,來實現圓的擴散動畫,代碼如下:

   private void doAnimCicle1(){
        //這裡起始圓以中心圓的高度作直徑
        ValueAnimator valueAnimator = ValueAnimator.ofObject(new RadiusEvaluator(),new SearchRadius(dsCenterH/2),new SearchRadius(centerX));
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                circleRadius1 = (SearchRadius)animation.getAnimatedValue();
                invalidate();
            }
        });
        valueAnimator.setDuration(delayTime);        //控制動畫的執行時間
        valueAnimator.setInterpolator(new DecelerateInterpolator());  //這裡使用減速插值器
        valueAnimator.setRepeatMode(ValueAnimator.RESTART);     //設置重復方式
        valueAnimator.setRepeatCount(ValueAnimator.INFINITE);   //設置無限重復
        valueAnimator.start();
    }

然後在初始化的時候調用 doAnimCicle1方法來啟動動畫
實現代碼比較簡單,在這裡通過ofObject 自定義Evalutor的方式來實現,熟悉一下自定義Evalutor的用法,此處使用ofFloat
就可以實現,實際使用 ofFloat 就可以了。
現在在onDraw 裡面繪制當前的圓

canvas.save();  
canvas.drawCircle(centerX, centerY, circleRadius1.getRadius(), mPaint);
canvas.restore();

效果如下:

這裡寫圖片描述

一個圓繪制成功了,接著就可以繪制余下的圓了,實現原理一樣,

private void doAnimCicle2(){

    ValueAnimator valueAnimator = ValueAnimator.ofObject(new RadiusEvaluator(),new SearchRadius(dsCenterH/2),new SearchRadius(centerX));
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            circleRadius1 = (SearchRadius)animation.getAnimatedValue();  
            invalidate();
        }
    });
    valueAnimator.setDuration(delayTime);        //控制動畫的執行時間
    valueAnimator.setStartDelay(delayTime/4);    //設置延時開始的時間
    valueAnimator.setInterpolator(new DecelerateInterpolator());  //這裡使用減速插值器
    valueAnimator.setRepeatMode(ValueAnimator.RESTART);     //設置重復方式
    valueAnimator.setRepeatCount(ValueAnimator.INFINITE);   //設置無限重復
    valueAnimator.start();
}

... 省略其他的實現。

在這裡通過延時啟動動畫,實現圓的先後繪制順序setStartDelay根據實際需要設置,在這裡,將delayTime 分成4份,均勻分配,看起來均勻變化。

現在來看一下實現效果:
這裡寫圖片描述

4個圓的效果有了,此時並沒有顏色慢慢變淡的效果,只需要在每次繪制圓形的時候將畫筆的透明度改變就可以了

mPaint.setAlpha(((centerX-circleRadius2.getRadius())*circleAlpha)/centerX);

這裡計算出的結果根據圓的半徑增大而減小。

3 實現游標轉動

 //繪制光標的圖片
        canvas.save();
       dsCursorW = drawableSearchCursor.getIntrinsicWidth();
       dsCursorH = drawableSearchCursor.getIntrinsicHeight();
       drawableSearchCursor.setBounds(centerX- (dsCursorW/2),centerY- (dsCursorH/2), centerX+ (dsCursorW/2),centerY+(dsCursorH/2));   
       drawableSearchCursor.draw(canvas);
       canvas.restore();

此時,游標圖片已經繪制好了,下面來實現它的轉動,只需要不斷的旋轉畫布,就可以實現轉動效果。
先來獲取旋轉角度的變化值

private void doAnimCursor(){

    ValueAnimator valueAnimator = ValueAnimator.ofInt(0,centerX);
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            circleRadius = (int)animation.getAnimatedValue();
            degree = (circleRadius*2)*360/centerX;  //畫布從0到360度進行旋轉,*2表示一個圓動作完,游標轉動2圈
            invalidate();
        }
    });
    valueAnimator.setDuration(delayTime);
    valueAnimator.setInterpolator(new LinearInterpolator());
    valueAnimator.setRepeatMode(ValueAnimator.RESTART);
    valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
    valueAnimator.start();
}

在獲取到變化的角度值後通過

canvas.rotate(degree,centerX,centerY);  //旋轉畫布,實現游標以中心點旋轉

就可以實現一個動態的效果。至此,就已經實現了開篇的效果

這裡寫圖片描述
相關代碼如下:

SearchAnimation

/**
 * Created by Mirko on 2016/11/9 19:09.
 */

public class SearchAnimation extends View{

    private Context mContext;
    private Paint   mPaint;
    private int    centerX,centerY;//屏幕的中心點
    private int    dsCenterW,dsCenterH;//中心圖片的寬高
    private int    dsCursorW,dsCursorH;//光標圖片的寬高
    private int    strokWidth = 5;    //畫筆大小
    private int    circleAlpha = 70;
    private int    delayTime = 8000;  //一個圓動畫執行的時間
    private float  degree;
    private int circleRadius ;
    private SearchRadius circleRadius1 = new SearchRadius(0);
    private SearchRadius circleRadius2 = new SearchRadius(0);
    private SearchRadius circleRadius3 = new SearchRadius(0);
    private SearchRadius circleRadius4 = new SearchRadius(0);

    private float circleRadiusF;

    private ValueAnimator valueAnimator;

    private Drawable drawableSearchCursor;
    private Drawable drawableSearchCenter;


    public SearchAnimation(Context context) {
        super(context);
    }

    public SearchAnimation(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context,attrs);
    }

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

       private void init(Context context,AttributeSet attrs){
        initAttrs(context,attrs);
        initPaint();
        initAnim();
    }

    /**
     * 取得相關自定義屬性
     * @param context
     * @param attrs
     */
    private void initAttrs(Context context,AttributeSet attrs){
        mContext = context;
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.SearchAnimation);
        drawableSearchCenter  = typedArray.getDrawable(R.styleable.SearchAnimation_drawable_search_center);
        drawableSearchCursor  = typedArray.getDrawable(R.styleable.SearchAnimation_drawable_search_cursor);
        typedArray.recycle();
    }

    private void initPaint(){
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(0X46FC3232);
    }

    private void initAnim(){
        dsCenterW = drawableSearchCenter.getIntrinsicWidth();          //獲取到中心圖片的寬高
        dsCenterH = drawableSearchCenter.getIntrinsicHeight();
        centerX = ViewSizeHelper.getDeviceWidth((Activity) mContext)/2; //獲取到屏幕的寬高
        centerY = ViewSizeHelper.getDeviceHeight((Activity) mContext)/2;
        doAnimCicle1();
        doAnimCicle2();
        doAnimCicle3();
        doAnimCicle4();
        doAnimCursor();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
       //首先來繪制中心的圖片
        drawableSearchCenter.setBounds(centerX- (dsCenterW/2),centerY- (dsCenterH/2), centerX+ (dsCenterW/2),centerY+(dsCenterH/2));
        drawableSearchCenter.draw(canvas);

        //繪制光標的圖片
        canvas.save();
        canvas.rotate(degree,centerX,centerY);  //旋轉畫布,實現游標的旋轉
        dsCursorW = drawableSearchCursor.getIntrinsicWidth();
        dsCursorH = drawableSearchCursor.getIntrinsicHeight();
        drawableSearchCursor.setBounds(centerX- (dsCursorW/2),centerY- (dsCursorH/2), centerX+ (dsCursorW/2),centerY+(dsCursorH/2));
        drawableSearchCursor.draw(canvas);
        canvas.restore();

        //繪制圓,4個
        mPaint.setStrokeWidth(strokWidth);
        canvas.save();
        mPaint.setAlpha(((centerX-circleRadius1.getRadius())*circleAlpha)/centerX); //設置透明度
        canvas.drawCircle(centerX, centerY, circleRadius1.getRadius(), mPaint);
        canvas.restore();

        canvas.save();
        mPaint.setAlpha(((centerX-circleRadius2.getRadius())*circleAlpha)/centerX);
        canvas.drawCircle(centerX, centerY, circleRadius2.getRadius(), mPaint);
        canvas.restore();

        canvas.save();
        mPaint.setAlpha(((centerX-circleRadius3.getRadius())*circleAlpha)/centerX);
        canvas.drawCircle(centerX, centerY, circleRadius3.getRadius(), mPaint);
        canvas.restore();

        canvas.save();
        mPaint.setAlpha(((centerX-circleRadius4.getRadius())*circleAlpha)/centerX);
        canvas.drawCircle(centerX, centerY, circleRadius4.getRadius(), mPaint);
        canvas.restore();
    }

    private void setAnimParams(ValueAnimator valueAnimator){
        valueAnimator.setDuration(delayTime);
        valueAnimator.setInterpolator(new DecelerateInterpolator());
        valueAnimator.setRepeatMode(ValueAnimator.RESTART);
        valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
        valueAnimator.start();
    }

    private void doAnimCicle1(){

        ValueAnimator valueAnimator = ValueAnimator.ofObject(new RadiusEvaluator(),new SearchRadius(dsCenterH/2),new SearchRadius(centerX));
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                circleRadius1 = (SearchRadius)animation.getAnimatedValue();
                invalidate();
            }
        });
        setAnimParams(valueAnimator);
    }
    private void doAnimCicle2(){

        ValueAnimator valueAnimator = ValueAnimator.ofObject(new RadiusEvaluator(),new SearchRadius(dsCenterH/2),new SearchRadius(centerX));
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                circleRadius2 = (SearchRadius)animation.getAnimatedValue();
                invalidate();
            }
        });
        valueAnimator.setStartDelay(delayTime/4);
        setAnimParams(valueAnimator);
    }
    private void doAnimCicle3(){

        ValueAnimator valueAnimator = ValueAnimator.ofObject(new RadiusEvaluator(),new SearchRadius(dsCenterH/2),new SearchRadius(centerX));
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                circleRadius3 = (SearchRadius)animation.getAnimatedValue();
                invalidate();
            }
        });
        valueAnimator.setStartDelay(delayTime/2);
        setAnimParams(valueAnimator);
    }
    private void doAnimCicle4(){

        ValueAnimator valueAnimator = ValueAnimator.ofObject(new RadiusEvaluator(),new SearchRadius(dsCenterH/2),new SearchRadius(centerX));
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                circleRadius4 = (SearchRadius)animation.getAnimatedValue();
                invalidate();
            }
        });
        valueAnimator.setStartDelay(delayTime/4*3);
        setAnimParams(valueAnimator);
    }

    private void doAnimCursor(){

        ValueAnimator valueAnimator = ValueAnimator.ofInt(0,centerX);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                circleRadius = (int)animation.getAnimatedValue();
                degree = (circleRadius*2)*360/centerX;  //畫布從0到360度進行旋轉
                invalidate();
            }
        });
        valueAnimator.setDuration(delayTime);
        valueAnimator.setInterpolator(new LinearInterpolator());
        valueAnimator.setRepeatMode(ValueAnimator.RESTART);
        valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
        valueAnimator.start();
    }

}

activity_search.xml




    

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