您的位置:首页 > 移动开发 > Android开发

Android 贝塞尔曲线的魅力

2015-11-25 17:50 537 查看
前几天在手机CSDN客户端看到一个QQ红点拖拽消失的效果,感觉挺好的,又回想到以前见到的诸如一下效果,感觉挺炫酷的,于是就看了下QQ拖拽的代码,记下笔记。







这个是在泡网上找到

还有一个指示器的效果,那个一时半会找不见了。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地带



。我们需要先确定控制点,控制点的坐标是(手指触点+上开始点)/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