Android之二階貝塞爾曲線的波浪頭像(三階的愛心飛出)

1、寫這個demo主要是因爲一個同事給我看了一個ios的效果,因爲感覺好玩所以我就寫了android樣式的,具體的效果就如下圖展示(圖是ios的gif不過效果是一樣的),有需要的朋友在下面會給出下載地址
這裏寫圖片描述

首先分析一下我的做法,我是將波浪的部分和頭像分開考慮,根據波浪的移動高度將頭像畫出
這裏寫圖片描述

一、定義屬性
其實我在做的時候我是直接開始畫,畫完了纔去優化自定義屬性,然而現在這些過程已經不重要了,我就先介紹下定義的屬性分別都是什麼含義。

<mmf.com.bubblingdemo.CorrugateView
        android:id="@+id/cv_waves"
        android:layout_width="match_parent"
        android:layout_marginTop="100dp"
        app:imgSize="50dp"
        app:waveHeight="20dp"
        app:rollTime="20"
        app:rollDistance="5"
        android:layout_height="70dp" />

app:imgSize=”50dp”定義的是頭像的大小
app:waveHeight=”20dp”波浪的高度
app:rollTime=”20”移動一次的時間
app:rollDistance=”5”移動一次的距離,像素

二、開始畫CorrugateView這個控件
(1)獲取所有屬性的值和初始化所需要的畫筆

public void init(Context context, AttributeSet attrs) {
        TypedArray attr = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CorrugateView, 0, 0);
        try {
            imgSize = (int) attr.getDimension(R.styleable.CorrugateView_imgSize, getResources().getDimensionPixelSize(
                    R.dimen.top_distance));
            waveHeight = (int) attr.getDimension(R.styleable.CorrugateView_waveHeight, getResources().getDimensionPixelSize(
                    R.dimen.top_distance_20));
            rollTime = attr.getInteger(R.styleable.CorrugateView_rollTime, 30);
            rollDistance = attr.getInteger(R.styleable.CorrugateView_rollDistance, 5);
        } finally {
            attr.recycle();
        }
        length = rollDistance;
        //保存上面一條曲線的數組
        mPointsList = new ArrayList<Point>();
        //保存下面一條曲線的數組
        mPointsListBottom = new ArrayList<Point>();
        //畫上面曲線的畫筆和線
        mWavePath = new Path();
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setColor(getResources().getColor(R.color.white));
        //畫下面曲線的畫筆和線
        mWavePathBottom = new Path();
        mPaintBottom = new Paint();
        mPaintBottom.setAntiAlias(true);
        mPaintBottom.setStyle(Paint.Style.FILL);
        mPaintBottom.setColor(getResources().getColor(R.color.top_withe));
    }

(2)獲取控件的寬高和初始化要畫的波浪的每個點

   @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mWidth = getMeasuredWidth();
        //控件高度=圖片的高度加上波浪的高度
        mHeight = waveHeight + imgSize;
        //初始化每個點
        initPoint();
        invalidate();
        //開啓一個計時器
        if (timer == null)
            start();
    }

initPoint();這個方法就是畫二階貝塞爾曲線的每個點,具體看代碼,因爲有點長就不貼進來了
start();開啓一個計時器,主要作用是在一定時間按一定的距離將曲線向右移動
(3)畫曲線

   @Override
    protected void onDraw(Canvas canvas) {
        //畫兩條曲線
        mWavePath.reset();
        mWavePathBottom.reset();
        mWavePathBottom.moveTo(mPointsListBottom.get(0).x, mPointsListBottom.get(0).y);
        mWavePathBottom.quadTo(mPointsListBottom.get(1).x, mPointsListBottom.get(1).y, mPointsListBottom.get(2).x, mPointsListBottom.get(2).y);
        mWavePathBottom.quadTo(mPointsListBottom.get(3).x, mPointsListBottom.get(3).y, mPointsListBottom.get(4).x, mPointsListBottom.get(4).y);
        mWavePathBottom.quadTo(mPointsListBottom.get(5).x, mPointsListBottom.get(5).y, mPointsListBottom.get(6).x, mPointsListBottom.get(6).y);
        mWavePathBottom.quadTo(mPointsListBottom.get(7).x, mPointsListBottom.get(7).y, mPointsListBottom.get(8).x, mPointsListBottom.get(8).y);
        mWavePathBottom.quadTo(mPointsListBottom.get(9).x, mPointsListBottom.get(9).y, mPointsListBottom.get(10).x, mPointsListBottom.get(10).y);
        mWavePathBottom.lineTo(mPointsListBottom.get(10).x, mHeight);
        mWavePathBottom.lineTo(mPointsListBottom.get(0).x, mHeight);
        mWavePathBottom.lineTo(mPointsListBottom.get(0).x, mPointsListBottom.get(0).y);
        mWavePathBottom.close();
        canvas.drawPath(mWavePathBottom, mPaintBottom);
        mWavePath.moveTo(mPointsList.get(0).x, mPointsList.get(0).y);
        mWavePath.quadTo(mPointsList.get(1).x, mPointsList.get(1).y, mPointsList.get(2).x, mPointsList.get(2).y);
        mWavePath.quadTo(mPointsList.get(3).x, mPointsList.get(3).y, mPointsList.get(4).x, mPointsList.get(4).y);
        mWavePath.quadTo(mPointsList.get(5).x, mPointsList.get(5).y, mPointsList.get(6).x, mPointsList.get(6).y);
        mWavePath.quadTo(mPointsList.get(7).x, mPointsList.get(7).y, mPointsList.get(8).x, mPointsList.get(8).y);
        mWavePath.lineTo(mPointsList.get(8).x, mHeight);
        mWavePath.lineTo(mPointsList.get(0).x, mHeight);
        mWavePath.lineTo(mPointsList.get(0).x, mPointsList.get(0).y);
        mWavePath.close();
        canvas.drawPath(mWavePath, mPaint);
        //畫頭像
        Bitmap bitmap = BitmapFactory.decodeResource(this.getContext()
                .getResources(), R.mipmap.icon_2017);
        drawImage(canvas, bitmap, (mWidth - imgSize) / 2, (int) getHeigthIcon() - imgSize,
                imgSize, imgSize, 0, 0, mPaint);
        //當移動的長度大於等於屏幕寬度重置點的座標
        if (allLength >= mWidth) {
            resetPoints();
            allLength = 0;
        }
    }

getHeigthIcon()這個方法比較重要,控制着頭像的上下移動,主要運用貝塞爾曲線的二階公式計算頭像的高度,下圖所示
這裏寫圖片描述

    /**
     * 獲取頭像中心的x對應的曲線的y值
     * @return
     */
    private float getHeigthIcon() {
        //移動的比率
        float t = (float) allHeight * 2 / mWidth;
        float y;
        //ismHeight爲true表示向下移動 false表示向上移動
        if (ismHeight) {
            //二價的貝塞爾曲線公式計算下面的曲線的根據t變化的高度
            y = mPointsList.get(2).y * (1 - t) * (1 - t)
                    + 2 * mPointsList.get(3).y * t * (1 - t)
                    + mPointsList.get(4).y * t * t;
        } else {
            //二價的貝塞爾曲線公式計算上面的曲線的根據t變化的高度
            y = mPointsList.get(0).y * (1 - t) * (1 - t)
                    + 2 * mPointsList.get(1).y * t * (1 - t)
                    + mPointsList.get(2).y * t * t;
        }
        return y;
    }

drawImage(Canvas canvas, Bitmap blt, int x, int y, int w,int h, int bx, int by, Paint paint)畫圖片的方法,具體看代碼,至此一個波浪的頭像就算完成啦!感興趣的下demo去看啦!

哦!差點忘了還有一個三階的愛心,demo的LoveLayout.java這個文件喲!感興趣的自己去看喲!

效果效果圖,我又忘了!如下所示,裏面使用了透明度的漸變,所以越高就越透明瞭,每個愛心的路徑都是一條隨機的三階貝塞爾曲線,demo中只要點界面就會拋出一個愛心,自己去欣賞吧!
這裏寫圖片描述
demo下載地址:https://github.com/972242736/BubblingDemo.git

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