一、概念

   1、先讲一下什么是贝塞尔曲线

         在数学的数值分析领域中,贝赛尔曲线(Bézier曲线)是电脑图形学中相当重要的参数曲线。更高维度的广泛化贝塞尔曲线就称作贝塞尔曲面,其中贝塞尔三角是一种特殊的实例。 

    2、贝塞尔曲线的目的又是什么呢

          利用贝塞尔曲线,我们能实现平滑的手势轨迹效果 ,还有比如说很多酷炫的效果基本也是有贝塞尔曲线来实现的,或者也可以说是形变的动画,举个小例子 QQ未读消息的拖拽球就是贝塞尔曲线实现的,说了一些想必你们也不是很明白, 那好下面我们来看效果图 看看对比,我们仔细的点开图片去看会发现第一张画出来的那个线条看起来是非常的圆润的,而第二张图片的那个线条看起来就有很多角,对第一张就是拿贝塞尔曲线实现的,想必现在你们会多多少少明白了很多。

自定义控件之贝赛尔曲线实现手势轨迹


  自定义控件之贝赛尔曲线实现手势轨迹

     3、Path类中的四个方法与贝赛尔曲线相关,如下:

     

//二阶贝赛尔  
public void quadTo(float x1, float y1, float x2, float y2)
public void rQuadTo(float dx1, float dy1, float dx2, float dy2)
//三阶贝赛尔  
public void cubicTo(float x1, float y1, float x2, float y2,float x3, float y3)
public void rCubicTo(float x1, float y1, float x2, float y2,float x3, float y3)

    在我们本篇文章中用到的方法就是第一个 quadTo()方法。


   二、invalidate与postInvalidate方法的详细介绍

         1、invalidate

       该方法的调用会引起View树的重绘,常用于内部调用(比如 setVisiblity())或者需要刷新界面的时候,需要在主线程(即UI线程)中调用该方法。那么我们来分析一下它的实现。 

          2、postInvalidate

        这个方法与invalidate方法的作用是一样的,都是使View树重绘,但两者的使用条件不同,postInvalidate是在非UI线程中调用,invalidate则是在UI线程中调用。 

    三、代码的实现

      没用贝塞尔曲线实现的自定义View类 MyView:

   package com.zero.cui.gesturetrackdemo;


import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;


/**
 * Created by y on 2018/5/4.
 */


public class MyView extends View {
    private Path mPath = new Path();


    public MyView(Context context) {
        super(context);
    }


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


    @Override
    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);


    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Paint paint = new Paint();
        paint.setColor(Color.BLUE);
        paint.setStyle(Paint.Style.STROKE);


        canvas.drawPath(mPath,paint);
    }


    public void reset(){
        mPath.reset();
        invalidate();
    }
}


  利用贝塞尔曲线实现的View类  MyView:

package com.zero.cui.gesturetrackdemo;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * Created by y on 2018/5/4.
 */

public class MyView extends View {
    private Path mPath = new Path();
    private float mPreX,mPreY;
    public MyView(Context context) {
        super(context);
    }

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

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN: {
                mPath.moveTo(event.getX(), event.getY());
                mPreX = event.getX();
                mPreY = event.getY();
                return true;
            }
            case MotionEvent.ACTION_MOVE:
                float endX = (mPreX+event.getX())/2;
                float endY = (mPreY+event.getY())/2;
                mPath.quadTo(mPreX,mPreY,endX,endY);
                mPreX = event.getX();
                mPreY =event.getY();
//                使View树重绘
                invalidate();
                break;
            default:
                break;
        }
        return super.onTouchEvent(event);

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Paint paint = new Paint();
        paint.setColor(Color.BLUE);
        paint.setStyle(Paint.Style.STROKE);

        canvas.drawPath(mPath,paint);
    }

    public void reset(){
        mPath.reset();
//        使View树重绘
        postInvalidate();
    }
}

     布局 activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent">
    <Button
        android:id="@+id/reset"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="重置"/>

    <com.zero.cui.gesturetrackdemo.MyView
        android:id="@+id/myview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>


     Activity:

package com.zero.cui.gesturetrackdemo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final MyView myView = (MyView)findViewById(R.id.myview);
        Button reset = (Button) findViewById(R.id.reset);
        reset.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                myView.reset();
            }
        });

    }


}



相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2021-07-08
  • 2021-12-22
  • 2022-12-23
  • 2021-12-05
  • 2021-05-25
猜你喜欢
  • 2022-12-23
  • 2021-11-16
  • 2021-05-27
  • 2021-12-28
  • 2022-12-23
  • 2021-07-04
相关资源
相似解决方案