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

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

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

小动画之“绘画板”(二阶贝塞尔曲线)_第1张图片
如左图,使用一阶贝塞尔曲线绘制,图线不光滑,会有明显折线效果;
如右图,使用二阶贝塞尔曲线,图线光滑圆润。


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

小动画之“绘画板”(二阶贝塞尔曲线)_第2张图片


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();
        }
        
    	@Override
        public boolean onTouchEvent(MotionEvent event) {
        	……
        	return super.onTouchEvent(event);
        }
        
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            canvas.drawPath(mPath, mPaint);
        }
    }
    

4.2 重写 OnTouchEvent() 函数

  1. 调用 Path 的 moveTo() 和 lineTo() 函数将手势经过的点连接起来。
    @Override
    public 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 取值,请参考如图理解;
    小动画之“绘画板”(二阶贝塞尔曲线)_第3张图片

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自定义控件开发入门与实战》_启舰》;

你可能感兴趣的:(Android学习总结)