1、手势轨迹
2、水波纹效果
电池充电时,有些手机会显示水波纹效果,就是这样做出来的。
贝赛尔曲线公式
主要用到一阶贝赛尔曲线和二阶贝赛尔曲
一阶贝赛尔曲线
总而言之:对于一阶贝赛尔曲线,大家可以理解为在起始点和终点形成的这条直线上,匀速移动的点。
二阶贝赛尔曲
钢笔工具所使用的路径弯曲效果就是二阶贝赛尔曲线。
二、Android中贝赛尔曲线之quadTo
1、quadTo使用原理
public void quadTo(float x1, float y1, float x2, float y2)
参数中(x1,y1)是控制点坐标,(x2,y2)是终点坐标
大家可能会有一个疑问:有控制点和终点坐标,那起始点是多少呢?
整条线的起始点是通过Path.moveTo(x,y)来指定的,而如果我们连续调用quadTo(),前一个quadTo()的终点,就是下一个quadTo()函数的起点;如果初始没有调用Path.moveTo(x,y)来指定起始点,则默认以控件左上角(0,0)为起始点;
--
Path path = new Path(); path.moveTo(100,300); path.quadTo(200,200,300,300); path.quadTo(400,400,500,300); canvas.drawPath(path,paint);
第一个起始点是需要调用path.moveTo(100,300)来指定的,之后后一个path.quadTo的起始点是以前一个path.quadTo的终点为起始点的。
-------------------
总结:
- 整条线的起始点是通过Path.moveTo(x,y)来指定的,如果初始没有调用Path.moveTo(x,y)来指定起始点,则默认以控件左上角(0,0)为起始点;
- 而如果我们连续调用quadTo(),前一个quadTo()的终点,就是下一个quadTo()函数的起点;
public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: { mPath.moveTo(event.getX(), event.getY()); return true; } case MotionEvent.ACTION_MOVE: mPath.lineTo(event.getX(), event.getY()); postInvalidate(); break; default: break; } return super.onTouchEvent(event); }
第一:有关在case MotionEvent.ACTION_DOWN时return true的问题:return true表示当前控件已经消费了下按动作,之后的ACTION_MOVE、ACTION_UP动作也会继续传递到当前控件中;如果我们在case MotionEvent.ACTION_DOWN时return false,那么后序的ACTION_MOVE、ACTION_UP动作就不会再传到这个控件来了。有关动作拦截的知识,后续会在这个系列中单独来讲,大家先期待下吧。
第二:这里重绘控件使用的是postInvalidate();而我们以前也有用Invalidate()函数的。这两个函数的作用都是用来重绘控件的,但区别是Invalidate()一定要在UI线程执行,如果不是在UI线程就会报错。而postInvalidate()则没有那么多讲究,它可以在任何线程中执行,而不必一定要是主线程。其实在postInvalidate()就是利用handler给主线程发送刷新界面的消息来实现的,所以它是可以在任何线程中执行,而不会出错。而正是因为它是通过发消息来实现的,所以它的界面刷新可能没有直接调Invalidate()刷的那么快。
所以在我们确定当前线程是主线程的情况下,还是以invalide()函数为主。当我们不确定当前要刷新页面的位置所处的线程是不是主线程的时候,还是用postInvalidate为好;
这里我是故意用的postInvalidate(),因为onTouchEvent()本来就是在主线程中的,使用Invalidate()是更合适的。
---------------------
Path类中的moveTo和lineTo的区别
moveto 是移动起始点
lineto是画线
使用Path.lineTo()所存在问题和Path.quadTo对比
在两个点连接处有明显的转折,而且在S顶部位置横纵坐标变化比较快的位置,看起来跟图片这大后的马赛克一样;利用Path绘图,是不可能出现马赛克的,因为除了Bitmap以外的任何canvas绘图全部都是矢量图,也就是利用数学公式来作出来的图,无论放在多大屏幕上,都不可能会出现马赛克!这里利用Path绘图,在S顶部之所以看起来像是马赛克是因为这个S是由各个不同点之间连线写出来的,而之间并没有平滑过渡,所以当坐标变化比较剧烈时,线与线之间的转折就显得特别明显了。
所以要想优化这种效果,就得实现线与线之间的平滑过渡,很显然,二阶贝赛尔曲线就是干这个事的。下面我们就利用我们新学的Path.quadTo函数来重新实现下移动轨迹效果。
---------------------
使用Path.lineTo()的最大问题就是线段转折处不够平滑。Path.quadTo()可以实现平滑过渡
第一句:path.rQuadTo(100,-100,200,0);是建立在(100,300)这个点基础上来计算相对坐标的。
所以
控制点X坐标=上一个终点X坐标+控制点X位移 = 100+100=200;
控制点Y坐标=上一个终点Y坐标+控制点Y位移 = 300-100=200;
终点X坐标 = 上一个终点X坐标+终点X位移 = 100+200=300;
终点Y坐标 = 上一个终点Y坐标+控制点Y位移 = 300+0=300;
所以这句与path.quadTo(200,200,300,300);对等的
第二句:path.rQuadTo(100,100,200,0);是建立在它的前一个终点即(300,300)的基础上来计算相对坐标的!
所以
控制点X坐标=上一个终点X坐标+控制点X位移 = 300+100=200;
控制点Y坐标=上一个终点Y坐标+控制点Y位移 = 300+100=200;
终点X坐标 = 上一个终点X坐标+终点X位移 = 300+200=500;
终点Y坐标 = 上一个终点Y坐标+控制点Y位移 = 300+0=300;
所以这句与path.quadTo(400,400,500,300);对等的
最终效果也是一样的。
通过这个例子,只想让大家明白一点:rQuadTo(float dx1, float dy1, float dx2, float dy2)中的位移坐标,都是以上一个终点位置为基准来做偏移的!
---------------------
Path.rQuadTo()
rQuadTo(float dx1, float dy1, float dx2, float dy2)中的位移坐标,都是以上一个终点位置为基准来做偏移的
public void rQuadTo(float dx1, float dy1, float dx2, float dy2)
dx1:控制点X坐标,表示相对上一个终点X坐标的位移坐标,可为负值,正值表示相加,负值表示相减;
dy1:控制点Y坐标,相对上一个终点Y坐标的位移坐标。同样可为负值,正值表示相加,负值表示相减;
dx2:终点X坐标,同样是一个相对坐标,相对上一个终点X坐标的位移值,可为负值,正值表示相加,负值表示相减;
dy2:终点Y坐标,同样是一个相对,相对上一个终点Y坐标的位移值。可为负值,正值表示相加,负值表示相减;
---------------------
Path.rQuadTo()和Path.quadTo()
Path.quadTo()是坐标
Path.rQuadTo()是相对坐标
水波纹的效果:
代码如下: