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

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