Android自定義View——擴散波浪按鈕

前言

勞動節(jié)快樂Q汀!档礁!O(∩_∩)O
雖然現(xiàn)在不是一個值得慶祝的時間角钩,因為美好的白天已經(jīng)過去了,再過不久大家就要回到公司或者課堂了。/(ㄒoㄒ)/~~
想做一個隨即匹配按鈕递礼,同學建議是做一個像波浪一樣向外擴散的按鈕惨险,同學在網(wǎng)上找了一個效果圖,看上去挺簡單的脊髓,就自己做了一個辫愉,下面是效果圖:


效果圖

我覺得用在只需要一個大按鈕的界面里面,是挺合適的将硝。
下面就來分享一下思路與代碼恭朗。

分析動畫

  1. 中間一個圓是不動的,里面有一個文字區(qū)域
  2. 外面的擴散的圓圈透明度是變化的依疼,從里面向外面越來越透明痰腮。
  3. 最開始是只有一條波紋的,慢慢才變成了3條律罢。

思路

  1. 先畫中間的不動的圓圈膀值。
  2. 繪制文字區(qū)域。
  3. 繪制周圍的圓圈弟翘,但是半徑要慢慢變大虫腋,如果有波紋超出了區(qū)域,那么繪制到里面稀余,形成一條新的波紋悦冀。
  4. 不斷重復上述過程。

代碼

為了節(jié)省空間睛琳,我省去了初始化代碼盒蟆、onMeasure()函數(shù)的代碼、還有一些很容易懂的成員變量师骗,大家有需要可以在這里查看完整的源代碼历等。

/**
 * Created by ICELEE on 5/1/2017.
 */

public class WaveButton extends View {

    private static final String TAG = "ICE";
    private Paint mPaint;
    private int mRadius;//里面圓圈的半徑
    private int mWidth;//控件的寬度
    private int mStrokeWidth;//波浪的寬度
    private int mFillColor;//圓圈填充顏色  
    private int mCircleStrokeColor;//圓圈邊緣顏色
    private int gapSize;//波浪之間的距離
    private int firstRadius;//第一個圓圈的半徑
    private int numberOfCircle;//顯示波浪的數(shù)量
    private int mLineColor;//波浪線的顏色
    private boolean isFirstTime = true;//是否是第一次開啟動畫
    private OnClickListener mClickListener;//點擊事件監(jiān)聽器
    private float mDownX,mDownY;//手指按下的坐標

    //省略了前面兩個少參數(shù)的構(gòu)造函數(shù) 源碼里面是用前面兩個調(diào)用這個
    public WaveButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context){
        //省略了各個成員變量的初始化過程
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //省略了測量的代碼  在源碼里面有簡單的測量
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.translate(mWidth/2,mWidth/2);//平移

        //畫中間的圓
        mPaint.setAlpha(255);
        mPaint.setColor(mFillColor);
        mPaint.setStyle(Paint.Style.FILL);
        canvas.drawCircle(0,0,mRadius,mPaint);
        //畫圓的邊
        mPaint.setStrokeWidth(mStrokeWidth);
        mPaint.setColor(mCircleStrokeColor);
        mPaint.setStyle(Paint.Style.STROKE);
        canvas.drawCircle(0,0,mRadius,mPaint);
        //畫文字
        Rect rect = new Rect();//文字的區(qū)域
        mTextPaint.getTextBounds(mText,0,mText.length(),rect);
        int height = rect.height();
        int width = rect.width();
        canvas.drawText(mText,-width/2,height/2,mTextPaint);

        //畫周圍的波浪
        firstRadius += 3;//每次刷新半徑增加3像素
        firstRadius %= (mWidth/2);//控制在控件的范圍中
        if(firstRadius<mRadius) isFirstTime =false;
        firstRadius = checkRadius(firstRadius);//檢查半徑的范圍
        mPaint.setColor(mLineColor);
        mPaint.setStyle(Paint.Style.STROKE);

        //畫波浪
        for (int i = 0; i < numberOfCircle; i++) {
            int radius = (firstRadius + i*gapSize ) % (mWidth/2);
            if(isFirstTime && radius>firstRadius) continue;
            radius = checkRadius(radius);//檢查半徑的范圍
            //用半徑來計算透明度  半徑越大  越透明
            double x = (mWidth/2 -radius)*1.0 /(mWidth/2 - mRadius);
            mPaint.setAlpha((int) (255*x));
            canvas.drawCircle(0,0,radius,mPaint);
        }

    }

    //檢查波浪的半徑  如果小于圓圈,那么加上圓圈的半徑
    private int checkRadius(int radius) {
        if(radius<mRadius){
            return radius+mRadius + gapSize;
        }
        return radius;
    }

    //dp轉(zhuǎn)像素
    public int dip2px(float dpValue) {
        final float scale = mContext.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    //不斷重繪  展示出波浪效果
    public void startAnimation(){
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                postInvalidate();
            }
        },0,50);

    }

    @Override
    public void setOnClickListener(OnClickListener l) {
        mClickListener = l;
    }

    //設置只有點擊圓圈才有點擊效果 點擊波浪不能觸發(fā)點擊效果
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){

            case MotionEvent.ACTION_DOWN:
                mDownX = event.getX();
                mDownY = event.getY();
                return checkIsInCircle((int)mDownX,(int)mDownY);

            case MotionEvent.ACTION_UP:
                int upX = (int) event.getX(),upY = (int) event.getY();
                if(checkIsInCircle(upX,upY) && mClickListener!=null){
                    mClickListener.onClick(this);//觸發(fā)點擊事件
                }
                break;

        }
        return true;
    }

    /**
     * 檢查點x,y是否落在圓圈內(nèi)
     * @param x
     * @param y
     * @return
     */
    private boolean checkIsInCircle(int x, int y){

        int centerX = (getRight() + getLeft())/2;
        int centerY = (getTop() + getBottom())/2;
        return  Math.pow(x-centerX,2)+Math.pow(y-centerY,2) < Math.pow(mRadius,2);
    }
}

懂了思路其實挺容易就能寫出這個辟癌,主要是如何讓波浪動起來寒屯。這里再畫個圖解釋解釋:

基本圖示

我們要把波浪的半徑radius模上mWidth/2,如果模后的值小于mRadius黍少,也就是radius超出了邊界寡夹,那么我們再加上mRadius就相當于又出來了一條新的波浪。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末厂置,一起剝皮案震驚了整個濱河市菩掏,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌昵济,老刑警劉巖智绸,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件野揪,死亡現(xiàn)場離奇詭異,居然都是意外死亡瞧栗,警方通過查閱死者的電腦和手機斯稳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來沼溜,“玉大人平挑,你說我怎么就攤上這事∠挡荩” “怎么了通熄?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長找都。 經(jīng)常有香客問我唇辨,道長,這世上最難降的妖魔是什么能耻? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任赏枚,我火速辦了婚禮,結(jié)果婚禮上晓猛,老公的妹妹穿的比我還像新娘饿幅。我一直安慰自己,他們只是感情好戒职,可當我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布栗恩。 她就那樣靜靜地躺著,像睡著了一般洪燥。 火紅的嫁衣襯著肌膚如雪磕秤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天捧韵,我揣著相機與錄音市咆,去河邊找鬼。 笑死再来,一個胖子當著我的面吹牛蒙兰,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播芒篷,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼搜变,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了梭伐?” 一聲冷哼從身側(cè)響起痹雅,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤仰担,失蹤者是張志新(化名)和其女友劉穎糊识,沒想到半個月后绩社,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡赂苗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年愉耙,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拌滋。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡朴沿,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出败砂,到底是詐尸還是另有隱情赌渣,我是刑警寧澤,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布昌犹,位于F島的核電站坚芜,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏斜姥。R本人自食惡果不足惜鸿竖,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望铸敏。 院中可真熱鬧缚忧,春花似錦、人聲如沸杈笔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽桩撮。三九已至敦第,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間店量,已是汗流浹背芜果。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留融师,地道東北人右钾。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像旱爆,于是被迫代替她去往敵國和親舀射。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內(nèi)容