贝塞尔曲线小练习

来不及了,快上车。。。。

这里写图片描述

不叨叨,上代码

/**
 * 类描述:
 * 作者:JiaoPeiRong on 2017/3/27 10:12
 */
public class MyBezier extends View {
    private Paint mPaint;
    private Path mPath;
    private float preX;
    private float preY;
    public MyBezier(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(3);
        mPaint.setColor(Color.RED);

        mPath = new Path();
    }

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

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                mPath.moveTo(event.getX() , event.getY());
                preX = event.getX();
                preY = event.getY();
                return true;
            case MotionEvent.ACTION_MOVE:
                float endX = (preX + event.getX()) / 2;
                float endY = (preY + event.getY()) / 2;
                mPath.quadTo(preX ,preY, endX , endY);
                preX = event.getX();
                preY = event.getY();
                invalidate();

                break;
            case MotionEvent.ACTION_UP:

                break;
        }

        return super.onTouchEvent(event);
    }
}

基础的贝塞尔曲线我就不讲了,网上一搜一大堆。
单纯的使用path也完全可以实现手势轨迹的捕捉,但是path不如贝塞尔曲线优雅,会有锯齿。代码很简单,我就不啰嗦了。
看这个:

这里写图片描述
波浪,没错,就是浪!
上代码:

/**
 * 类描述:
 * 作者:JiaoPeiRong on 2017/3/27 10:56
 */
public class MyBezier2 extends View {
    //波长
    private float line = 300;
    //开始绘制的Y轴坐标
    private float myY = 200;
    //每次改变的大小
    private float dx;
    private Paint mPaint;
    private Path mPath;
    public MyBezier2(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(Color.RED);
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mPaint.setStrokeWidth(3);

        mPath = new Path();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPath.reset();
        float halfLine = line / 2;
        mPath.moveTo(-line + dx , myY);
        for (float i = -halfLine ; i < getWidth() + halfLine ; i+=halfLine){
            mPath.rQuadTo(halfLine / 2 , 50 , halfLine , 0);
            mPath.rQuadTo(halfLine / 2 , -50 , halfLine , 0);
        }
        mPath.lineTo(getWidth() , getHeight());
        mPath.lineTo(0 , getHeight());
        mPath.close();
        canvas.drawPath(mPath , mPaint);
    }

    public void startAnim(){
        ValueAnimator animator = ValueAnimator.ofFloat(0,line);
        animator.setDuration(2000);
        animator.setRepeatCount(ValueAnimator.INFINITE);
        animator.setInterpolator(new LinearInterpolator());
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                dx = (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        animator.start();
    }
}

代码也灰常简单,无非就是画个曲线,然后动画让它动起来,哈哈~
看这个:

这里写图片描述
仿QQ的效果,代码也很简单哦

/**
 * 类描述:
 * 作者:JiaoPeiRong on 2017/3/27 11:30
 */
public class MyBezier3 extends FrameLayout {
    private float radius = 15;
    private float DEFAULT_RADIUS = 15;
    private float count = 200;
    //原位置的坐标
    private float startPointX = count;
    private float startPointY = count;
    //现位置的坐标
    private float curPointX = count;
    private float curPointY = count;
    private Paint p;
    private Path mPath;
    //是否在滑动
    private boolean isMove = false;
    //是否开始帧动画
    private boolean isAnimStart = false;
    private TextView tv;
    private ImageView iv;

    public MyBezier3(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        p = new Paint(Paint.ANTI_ALIAS_FLAG);
        p.setColor(Color.RED);
        p.setStyle(Paint.Style.FILL);

        mPath = new Path();

        //TextView
        ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        tv = new TextView(getContext());
        tv.setLayoutParams(layoutParams);
        tv.setPadding(5, 5, 5, 5);
        tv.setText("99+");
        tv.setTextSize(10);
        tv.setBackgroundResource(R.drawable.shape_tv_bg);
        tv.setTextColor(Color.WHITE);

        //ImageView
        iv = new ImageView(getContext());
        iv.setLayoutParams(layoutParams);
        iv.setImageResource(R.drawable.shape_iv_bg);
        iv.setVisibility(INVISIBLE);

        addView(tv);
        addView(iv);
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {

        if (isAnimStart) {
            tv.setX(count);
            tv.setY(count);
        } else {
            canvas.drawCircle(startPointX, startPointY, radius, p);
            calculatePath();
            canvas.drawPath(mPath, p);
            tv.setX(curPointX - tv.getWidth() / 2);
            tv.setY(curPointY - tv.getHeight() / 2);
        }
        super.dispatchDraw(canvas);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if (Math.abs(event.getX() - count) < radius && Math.abs(event.getY() - count) < radius) {
                    isMove = true;
                } else {
                    isMove = false;
                }
                return true;
            case MotionEvent.ACTION_MOVE:
                if (isMove) {
                    curPointX = event.getX();
                    curPointY = event.getY();
                }
                break;
            case MotionEvent.ACTION_UP:
                curPointX = count;
                curPointY = count;
                break;
        }
        invalidate();
        return super.onTouchEvent(event);
    }

    /**
     * 计算路径
     */
    private void calculatePath() {

        float x = curPointX;
        float y = curPointY;
        float startX = startPointX;
        float startY = startPointY;
        // 根据角度算出四边形的四个点
        float dx = x - startX;
        float dy = y - startY;
        double a = Math.atan(dy / dx);
        float offsetX = (float) (radius * Math.sin(a));
        float offsetY = (float) (radius * Math.cos(a));

        float distance = (float) Math.sqrt(Math.pow(y - startY, 2) + Math.pow(x - startX, 2));
        radius = DEFAULT_RADIUS - distance / 15;
        if (radius < 9) {
            radius = 9;
            isAnimStart = true;
            iv.setX(curPointX - iv.getWidth() / 2);
            iv.setY(curPointY - iv.getHeight() / 2);
            iv.setVisibility(VISIBLE);
            ((AnimationDrawable) iv.getDrawable()).start();
            tv.setVisibility(GONE);

        }
        // 根据角度算出四边形的四个点
        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;

        float anchorX = (startX + x) / 2;
        float anchorY = (startY + y) / 2;

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

源码奉上
参考资料

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
从2阶到7阶的贝赛尔曲线 private static final int MAX_COUNT = 7; // 贝塞尔曲线最大阶数 private static final int REGION_WIDTH = 30; // 合法区域宽度 private static final int FINGER_RECT_SIZE = 60; // 矩形尺寸 private static final int BEZIER_WIDTH = 10; // 贝塞尔曲线线宽 private static final int TANGENT_WIDTH = 6; // 切线线宽 private static final int CONTROL_WIDTH = 12; // 控制点连线线宽 private static final int CONTROL_RADIUS = 12; // 控制点半径 private static final int TEXT_SIZE = 40; // 文字画笔尺寸 private static final int TEXT_HEIGHT = 60; // 文本高度 private static final int RATE = 10; // 移动速率 private static final int HANDLER_WHAT = 100; private static final int FRAME = 1000; // 1000帧 private static final String[] TANGENT_COLORS = {"#7fff00", "#7a67ee", "#ee82ee", "#ffd700", "#1c86ee", "#8b8b00"}; // 切线颜色 private static final int STATE_READY = 0x0001; private static final int STATE_RUNNING = 0x0002; private static final int STATE_STOP = 0x0004; private static final int STATE_TOUCH = 0x0010; private Path mBezierPath = null; // 贝塞尔曲线路径 private Paint mBezierPaint = null; // 贝塞尔曲线画笔 private Paint mMovingPaint = null; // 移动点画笔 private Paint mControlPaint = null; // 控制点画笔 private Paint mTangentPaint = null; // 切线画笔 private Paint mLinePaint = null; // 固定线画笔 private Paint mTextPointPaint = null; // 点画笔 private Paint mTextPaint = null; // 文字画笔 private ArrayList mBezierPoints = null; // 贝塞尔曲线点集 private PointF mBezierPoint = null; // 贝塞尔曲线移动点 private ArrayList mControlPoints = null; // 控制点集 private ArrayList<ArrayList<ArrayList>> mTangentPoints; // 切线点集 private ArrayList<ArrayList> mInstantTangentPoints; private int mR = 0; // 移动速率 private int mRate = RATE; // 速率 private int mState; // 状态 private boolean mLoop = false; // 设置是否循环 private boolean mTangent = true; // 设置是否显示切线 private int mWidth = 0, mHe
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值