Android 贝塞尔曲线的魅力

前几天在手机CSDN客户端看到一个QQ红点拖拽消失的效果,感觉挺好的,又回想到以前见到的诸如一下效果,感觉挺炫酷的,于是就看了下QQ拖拽的代码,记下笔记。
Android 贝塞尔曲线的魅力_第1张图片Android 贝塞尔曲线的魅力_第2张图片

这个是在泡网上找到
还有一个指示器的效果,那个一时半会找不见了。UC浏览器新闻那一块的下拉刷新也是用了贝塞尔曲线的。

什么是贝塞尔曲线

在数学的数值分析领域中,贝塞尔曲线,
又称贝赛尔曲线(Bézier曲线)是电脑图形学中相当重要的参数曲线。更高维度的广泛化贝塞尔曲线就称作贝塞尔曲面,其中贝塞尔三角是一种特殊的实例。
贝塞尔曲线于1962年,由法国工程师皮埃尔·贝塞尔(Pierre
Bézier)所广泛发表,他运用贝塞尔曲线来为汽车的主体进行设计。贝塞尔曲线最初由Paul de Casteljau于1959年运用de
Casteljau算法开发,以稳定数值的方法求出贝塞尔曲线。
贝塞尔曲线在图形学中比较常见,我也是学过图形学的(没学成),贝塞尔曲线画出来的线条让人感觉很优美。

关于贝塞尔曲线的介绍:androidzhaoxiaogang
百度百科

Android中的贝塞尔曲线

Android SDK中为我们实现了二阶和三阶贝塞尔曲线,任意阶的贝塞尔曲线,sdk中并没有提供,不过找了个github的demo7叔。

二阶贝塞尔曲线

Path#quadTo 函数

/**
     * Add a quadratic bezier from the last point, approaching control point
     * (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for
     * this contour, the first point is automatically set to (0,0).
     *
     * @param x1 The x-coordinate of the control point on a quadratic curve
     * @param y1 The y-coordinate of the control point on a quadratic curve
     * @param x2 The x-coordinate of the end point on a quadratic curve
     * @param y2 The y-coordinate of the end point on a quadratic curve
     */
    public void quadTo(float x1, float y1, float x2, float y2) {
        isSimplePath = false;
        native_quadTo(mNativePath, x1, y1, x2, y2);
    }

4个参数的意思很明白,控制点的xy坐标,终点的xy坐标。


二阶示意图。关于在android中怎么使用就不说了,下面会说三阶的使用方法。

三阶贝塞尔曲线

Path#cubicTo 函数

public void cubicTo(float x1, float y1, float x2, float y2,
                        float x3, float y3) {
        isSimplePath = false;
        native_cubicTo(mNativePath, x1, y1, x2, y2, x3, y3);
    }

参数为第一个控制点的xy,第二个控制点的xy,终点,那么我们来看下如何使用(为了方便,下面使用的时候坐标写死)。

mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(1);
        mPaint.setTextSize(25);
        mPaint.setColor(Color.parseColor("#ee0000"));
        mPath = new Path();
        mPath.moveTo(5, 405);
        mPath.cubicTo(135,5,265,405,405,5);

哈哈,是不是很简单,只需要将path的起点移动至贝塞尔曲线的起点,然后将坐标套进去,接着在ondraw里面绘制就ok了。 看下这个的效果图。

就是这个效果,看起来很光滑对吧。

QQ红点的实现效果

博客地址找不见了,不过找的见github(前几天fork star啦,在这里对那个作者说声抱歉,没法贴csdn地址了)github地址 。
那么咱们就来看下其中的关键性代码和计算吧。

float offsetX = (float) (radius*Math.sin(Math.atan((y - startY) / (x - startX))));
        float offsetY = (float) (radius*Math.cos(Math.atan((y - startY) / (x - startX))));

        float x1 = startX - offsetX;
        float y1 = startY + offsetY;

        float x2 = x - offsetX;
        float y2 = y + offsetY;

        float x3 = x + offsetX;
        float y3 = y - offsetY;

        float x4 = startX + offsetX;
        float y4 = startY - offsetY;

        path.reset();
        path.moveTo(x1, y1);
        path.quadTo(anchorX, anchorY, x2, y2);
        path.lineTo(x3, y3);
        path.quadTo(anchorX, anchorY, x4, y4);
        path.lineTo(x1, y1);

上面的代码得配置一张图才好。下面这张图来自QQ地带
Android 贝塞尔曲线的魅力_第3张图片
。我们需要先确定控制点,控制点的坐标是(手指触点+上开始点)/2.

anchorX =  (event.getX() + startX)/2;
anchorY =  (event.getY() + startY)/2;

那么剩下的四个点怎么确定呢。

float offsetX = (float) (radius*Math.sin(Math.atan((y - startY) / (x - startX))));
        float offsetY = (float) (radius*Math.cos(Math.atan((y - startY) / (x - startX))));

上面的2行代码是什么意思呢。就是算出开始点那个圆的半径在X,Y轴上的投影距离。要注意XY轴和屏幕坐标轴的区别,这里算出来的是补角。所以产生了下面的看起来有点怪实际上是正确的代码。上面算出的x是没问题的,但是算出来的y却是-y。

float x1 = startX - offsetX;
        float y1 = startY + offsetY;

        float x2 = x - offsetX;
        float y2 = y + offsetY;

        float x3 = x + offsetX;
        float y3 = y - offsetY;

        float x4 = startX + offsetX;
        float y4 = startY - offsetY;

通过上面的代码就把需要的4个点的坐标计算出来了。
接下来说下爆炸的效果。效果很不错是吧,我们常常产生这样的幻觉,当觉得一个效果非常牛非常酷炫的时候,我们通常不会想到帧动画(因为帧动画现在用的比较少了),单却是是那些非常难的动画效果,可以在对性能消耗不大的情况下考虑帧动画。这里也不例外,好了,你们是不是跃跃欲试了么。去github下载代码看看吧。

小水滴的实现效果


,效果不是很好,不过没关系,还是能看的。效果为什么不是很好了,因为我这里不是像上面用的4个点,我这里用的3个点(省事)。看下和上面的那个类似。

float offsetX = (float) (50 * (Math.cos(Math.asin(50/centerY))));
                float offsetY = (float) (50 * (Math.sin(Math.asin(50/centerY))));
                mPath.reset();
                mPath.lineTo(200,0);
                mPath.quadTo(200,centerY/3,200-offsetX,centerY-offsetY);
                mPath.lineTo(200+offsetX, centerY-offsetY);
                mPath.quadTo(200,centerY/3,200,0);

本来想上张原理图的,但是没找到合适的绘图软件,就算了把。

总结

贝塞尔曲线在android中用起来并不难,但是用在什么地方,什么时候用,却是个很难的为题,就像QQ那个小红点一样,需要创意。

博客中有什么错误的还希望指出来。

你可能感兴趣的:(android)