Android貝塞爾曲線的簡單應用之——實現自定義圓形控件內水波紋自動上升效果Demo


下一篇:Android貝塞爾曲線的簡單應用之——實現仿美團點擊商品掉落購物車效果,附demo和工具類

先上效果:

在這裏插入圖片描述

gif可能看不到,上兩張截圖

在這裏插入圖片描述在這裏插入圖片描述

貝塞爾曲線知識的簡單應用,自定義了個圓形控件,控件內水波紋自動上升,通過幾個簡單的seekbar做了個簡單的顏色選擇器。
很早之前就聽過說貝塞爾曲線,只是一直沒時間好好學習一番,最近忙裏偷閒,便想着瞭解一下,網上關於貝塞爾曲線的解釋很多,這裏我就暫時不班門弄斧了,如果還不甚瞭解又有興趣瞭解的小夥伴,可以去看看這個作者的博客,其中關於貝塞爾曲線的介紹那篇寫的還挺通俗易懂的。

部分關鍵代碼如下:

1.爲了控件更靈活易於拓展,自定義一些屬性

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <declare-styleable name="BezierView">
            <!--水位上升動畫的執行時間-->
            <attr name="duration1" format="integer"/>
            <!--水波週期移動動畫的執行時間-->
            <attr name="duration2" format="integer"/>
            <!--水波高度-->
            <attr name="waveHeight" format="integer"/>
            <!--水波長度-->
            <attr name="waveWidth" format="integer"/>
            <!--初始點Y座標,即水位初始位置-->
            <attr name="originY" format="integer"/>
            <!--背景圓的顏色-->
            <attr name="cirColor" format="color"/>
            <!--背景圓的輪廓的顏色-->
            <attr name="cirSideColor" format="color"/>
        </declare-styleable>

2.創建自定義view,onDraw中的代碼如下:

    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //畫背景圓
        mCanvas.drawCircle(radius,radius,radius,bgCirPaint);
        //不斷的計算波浪的路徑
        calculatePath();
        //在背景圓上繪製水波
        mCanvas.drawPath(path,paint);
        //將畫好的圓繪製到畫布上
        canvas.drawBitmap(mbitmap,0,0,null);
        //繪製圓的輪廓(邊)
        canvas.drawCircle(radius,radius,radius,cirPaint);
    }

3.計算波浪的路徑path,這裏便用到了貝塞爾曲線來繪製水波紋的路徑:

     private void calculatePath() {
        
                //初始點
                path.moveTo(-waveWidth + dex, originY - dey);
                for (int i = -waveWidth; i < width + waveWidth; i += waveWidth) {
        
                    //二階貝塞爾曲線繪製
                    path.rQuadTo(waveWidth / 4, -waveHeight, waveWidth / 2, 0);
                    path.rQuadTo(waveWidth / 4, waveHeight, waveWidth / 2, 0);
                }
                //繪製連線
                path.lineTo(width, height);
                path.lineTo(0, height);
                path.close();//關閉當前輪廓。如果當前點不等於輪廓的第一個點,則自動添加線段,使其形成閉區間。
            }

4.動畫效果部分:水波上升和水波移動效果,都可以通過屬性動畫來實現,而且實現方式幾乎一樣,這裏是在自定義view內實現一個public的開啓動畫的方法供activity在適當地時候去調用:

    public void startAnimation() {
    
            //初始化水波效果動畫
            animator1 = ValueAnimator.ofFloat(0, 1);//定義一個值從0到1的控制值
            animator1.setDuration(duration2);//水波移動週期時長
            animator1.setRepeatCount(ValueAnimator.INFINITE);//設置循環次數,0爲1次,無窮盡的一直執行:ValueAnimator.INFINITE
            animator1.setInterpolator(new LinearInterpolator());//插值器,線性勻速播放動畫,不設置其實也是默認勻速
            //監聽
            animator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {
                    //獲取屬性動畫當前值(0-1)
                    float fraction = (float) animator1.getAnimatedValue();
                    dex = (int) (waveWidth * fraction);//根據動畫進行進度,動態修改整條波浪線的長度
                    //清空畫布
                    if (path != null)
                        path.reset();
                    //刷新
                    postInvalidate();
                }
            });
            //啓動動畫
            animator1.start();
    
            //初始化水位上升動畫
            animator2 = ValueAnimator.ofFloat(0, 1);//定義一個值從0到1的控制值
            animator2.setDuration(duration1);//水波上升週期時長
            animator2.setRepeatCount(0);//設置循環次數,0爲1次,無窮盡的一直執行:ValueAnimator.INFINITE
            animator2.setInterpolator(new LinearInterpolator());//插值器,線性勻速播放動畫,不設置其實也是默認勻速
            //監聽
            animator2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {
                    //獲取屬性動畫當前值(0-1)
                    float fraction = (float) animator2.getAnimatedValue();
                    dey = (int) ((height+waveHeight*2) * fraction);//根據動畫進度,dey的值會從0慢慢接近於heitht+waveHeight*2的高度
                    //清空畫布
                    if (path != null)
                        path.reset();
                    //刷新
                    postInvalidate();
                }
            });
            //啓動動畫
            animator2.start();
        }

關鍵代碼就是上面的這些啦,估計有經驗的小夥伴看到這裏已經知道怎麼做了,要是懶得自己寫,可以直接去下我的demo也行,demo中已有詳細註釋:

Demo下載地址:https://download.csdn.net/download/qq_37717853/10916906

項目參考博客:
1.https://www.cnblogs.com/wjtaigwh/p/6750184.html
2.https://blog.csdn.net/u013087553/article/details/68490170

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