小动画之“绘画板”(二阶贝塞尔曲线)

二阶贝塞尔曲线实现绘画板效果

  • 1. 什么是二阶贝塞尔曲线
  • 2. 曲线函数 quadTo()
  • 3. 原理分析
  • 4. 代码实现
    • 4.1 自定义控件
    • 4.2 重写 OnTouchEvent() 函数
    • 4.3 重写 onDraw() 方法
    • 4.4 注意
  • 5. rQuadTo() 函数

在这里插入图片描述
如左图,使用一阶贝塞尔曲线绘制,图线不光滑,会有明显折线效果;
如右图,使用二阶贝塞尔曲线,图线光滑圆润。


1. 什么是二阶贝塞尔曲线

在这里插入图片描述


2. 曲线函数 quadTo()

  1. 函数

    //二阶贝济埃曲线
    public void quadTo(float xl , float yl, float x2 , float y2);
    
  2. 参数

    (xl , y1) 是控制点 P1 坐标,(x2,y2)是终点 P2 坐标。

    起始点 P0 是通过 Path.moveTo(x,y)函数来指定的;
    如果连续调用quadTo() 函数,那么前一个 quadTo() 函数的终点就是下一个 quadTo() 函数的起始点。


3. 原理分析

  1. 捕捉手势轨迹

    在自定义控件中拦截 OnTouchEvent,根据手指的移动轨迹来绘制 Path;

  2. 实现方法:

    最简单的方法就是直接调用 Path.lineTo() 函数把各个点连接起来。

    效果如首图左侧所示,存在明显的折线效果。


4. 代码实现

4.1 自定义控件

  1. 在构造函数中初始化相关的参数;

    public class NormalGestureTrackView extends View {private Paint mPaint;private Path mPath;//起始点坐标private float mPreX;private float mPreY;//结束点坐标private float mEndX;private float mEndY;public NormalGestureTrackView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);mPaint.setColor(Color.RED);mPaint.setStrokeWidth(5);mPaint.setStyle(Paint.Style.STROKE);mPath = new Path();}@Overridepublic boolean onTouchEvent(MotionEvent event) {……return super.onTouchEvent(event);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawPath(mPath, mPaint);}
    }
    

4.2 重写 OnTouchEvent() 函数

  1. 调用 Path 的 moveTo() 和 lineTo() 函数将手势经过的点连接起来。
    @Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:mPreX = event.getX();mPreY = event.getY();mPath.moveTo(mPreX, mPreY);return true;case MotionEvent.ACTION_MOVE:if (GestureTrackActivity.isLineTo) {mEndX = event.getX();mEndY = event.getY();mPath.lineTo(mEndX, mEndY);} else {mEndX = (event.getX() + mPreX) / 2;mEndY = (event.getY() + mPreY) / 2;mPath.quadTo(mPreX, mPreY, mEndX, mEndY);mPreX = event.getX();mPreY = event.getY();}invalidate();break;default:break;}return super.onTouchEvent(event);}
  1. 注意:

    这里我在调用该 View 的 activity 中定义了静态布尔值常量 isLineTo ,默认为 true,默认使用 lineTo() 连接,当点击 btn 时取反;

    当 isLineTo 为 true 时,使用一个方法,为 false 时,使用二阶贝塞尔曲线;

  2. 关于 EndX 取值,请参考如图理解;
    在这里插入图片描述

4.3 重写 onDraw() 方法

  1. 画出轨迹

    @Override
    protected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawPath(mPath, mPaint);
    }
    

4.4 注意

  1. 在 MotionEvent.ACTION_DOWN 中 返回 true;并且没有 break;表示当前控件已经消费了下按动作,之后的ACTION_MOVE 、ACTION_UP 动作也会继续传递到当前/控件中:

  2. 重绘控件使用的是 postlnvalidate() 函数,也可以使用 Inval idate() 函数。这两个函数都可以重绘控件,

    区别是 Invalidate() 函数一定要在主线程中执行, 否则会报错
    postlnvalidate() 函数可以在任何线程中执行;


5. rQuadTo() 函数

publiC void rQuadTo(float dxl , float dyl, float dx2, float dy2)

具体实现与详解,请看:小动画之"波浪动画";


声明:本文整理自《《Android自定义控件开发入门与实战》_启舰》;


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部