实现弹性组件效果(贝塞尔曲线&&阻尼函数)

来源:互联网 发布:最优化方法 答案 编辑:程序博客网 时间:2024/06/11 17:56

1.贝塞尔曲线

贝塞尔曲线是一种画线的方法,主要是通过四个点确定一条线,首尾两个端点,中间两个点构成一条虚拟的标准线,曲线就根据这条线相切以及两个端点确定。

首先看看如何用贝塞尔曲线画出四分之一个圆:

请先参考这篇博客:http://blog.csdn.net/nibiewuxuanze/article/details/48103059#comments

总结起来,除了首尾两个端点外,中间两个点的位置是由端点和偏移量共同决定的。

如图,B的位置是A向左一个偏移量,C的位置是D向上一个偏移量。而且根据计算这个偏移量是直径/3.6。


2.画一个圆:

为了以后的使用方便,这里用上下左右四个顶点确定一个圆。

重写组件的onDraw方法:

Path path = new Path();        path.moveTo(xA,yA);        path.cubicTo(xA+offset,yA,xB,yB-offset,xB,yB);        path.cubicTo(xB,yB+offset,xC+offset,yC,xC,yC);        path.cubicTo(xC-offset,yC,0,yD+offset,xD,yD);        path.cubicTo(0,yD-offset,xA-offset,yA,xA,yA);        Paint paint=new Paint();        paint.setAntiAlias(true);        paint.setColor(backColor);        canvas.drawPath(path,paint);

四个点的位置可以根据半径计算得出。

这里的cubicTo就是用贝塞尔曲线画线的,参数中三个点的位置就是从本位置依次到达的三个点。经过四次贝塞尔画线回到起点,一个圆也就画好了。


3.改变顶点的位置:

首先要明白,在圆形的绘制过程中,偏移量是不变的,变的是顶点的位置。所以这里再定义一个变量extra,表示顶点在原位置上移动的距离。右顶点向右移动a,则上下两个顶点也向中间移动a,并向右移动a/2。

至于这个extra是多长,可以自己确定,我用的是半径的二分之一。

加上这个移动量之后,会发现画出的就是一个椭圆了。


4.利用阻尼函数实现动画效果:

动画效果其实就是不断改变extra的值并通知组件重画。可以使用属性动画,这里我直接用了一个子线程。

再定一个一个变量fudu,表示振动的幅度,0到1,乘上extra作为最终应用的移动量。接下来就是对fudu这个值的操作。

为了实现果冻一样的弹性效果,这里用了阻尼函数。


阻尼函数是一个不断振动的函数,我经过笨拙的代数实验取了(0,0.2)这样一个区间进行使用,数值会短暂振动并最终趋于1,由于我最后希望fudu值为0,也就是移动量为0,所以又减了1:

new Thread(new Runnable() {            @Override            public void run() {                while (true){                    handler.post(new Runnable() {                        @Override                        public void run() {                            invalidate();                        }                    });                    if (x<0.2f){                        x+=0.01f;                    }                    fudu = (float) (1 - Math.pow(Math.E, -1 * 5 * x) * Math.cos(30 * x));                    fudu -=1;                    if (fudu <0){                        fudu =0;                    }                    try {                        Thread.sleep(100);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        }).start();

5,30等值都是可以改变的,效果也会有变化。我的效果其实不太好,对阻尼函数更有研究的同志可以教教我。

invalidate用以通知组件进行更新,因为是UI操作所以借助了handler。


完整draw:


@Override    protected void onDraw(Canvas canvas) {        extra= fudu *radious/2;        offset=  radious*2/3.6f;        xA=radious+extra/2;        yA=extra;        xB=radious*2+extra;        yB=radious;        xC=radious+extra/2;        yC=radious*2-extra;        xD=0;        yD=yB;        Path path = new Path();        path.moveTo(xA,yA);        path.cubicTo(xA+offset,yA,xB,yB-offset,xB,yB);        path.cubicTo(xB,yB+offset,xC+offset,yC,xC,yC);        path.cubicTo(xC-offset,yC,0,yD+offset,xD,yD);        path.cubicTo(0,yD-offset,xA-offset,yA,xA,yA);        Paint paint=new Paint();        paint.setAntiAlias(true);        paint.setColor(backColor);        canvas.drawPath(path,paint);        super.onDraw(canvas);    }

0 0