1. 程式人生 > >Android自定義檢視-手指移動軌跡

Android自定義檢視-手指移動軌跡

今天看了大神寫的關於貝塞爾曲線的部落格,就寫下了關於手指軌跡的一篇部落格,

一、什麼是貝塞爾曲線

            貝塞爾曲線(Bézier curve),又稱貝茲曲線或貝濟埃曲線,是應用於二維圖形應用程式的數學曲線。一般的向量圖形軟體通過它來精確畫出曲線,貝茲曲線由線段與節點組成,節點是可拖動的支點,線段像可伸縮的皮筋,我們在繪圖工具上看到的鋼筆工具就是來做這種向量曲線的。貝塞爾曲線是計算機圖形學中相當重要的引數曲線,在一些比較成熟的點陣圖軟體中也有貝塞爾曲線工具,如PhotoShop等。

二、貝塞爾曲線公式

    

三、手指軌跡原理

          因為這個我們用的是自定義控制元件,所以我們建立一個finger的類整合View,重寫onDraw  onTouchEvent這個兩個方法

             public finger(Context context, @Nullable AttributeSet attrs)       需要這個構造方法

onDraw 是一個繪製方法,我們需要重寫這個繪製方法,達到繪製自由
onTouchEvent 這個是觸控事件的方法,我們需要重寫這個,回去手指觸控式螢幕幕的座標

        其實手指軌跡的原理也很簡單,就是通過onTouchEvent來獲取道手指的位置,來繪製path路徑即可。

四、分析程式碼

    這裡我先寫出全部的程式碼,後面我再來一一分析程式碼的作用:

    全部程式碼:

package com.campus.shopping.drawtext;

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

/**
 * Created by sang on 2018/6/24.
 */

public class MyView extends View {

    private Path mPath = new Path();
    private float mPreX,mPreY;

    public MyView(Context context, @Nullable 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();
                invalidate();
                break;
            default:
                break;
        }
        return super.onTouchEvent(event);
    }

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

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

        canvas.drawPath(mPath, paint);
    }
}

onTouchEvent方法:

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();
                invalidate();
                break;
            default:
                break;
        }
        return super.onTouchEvent(event);
    }

當手指按下觸發了ACTION_DOWN時,這裡我通過moveTo的方法繪製了第一個點,這個必須使用moveTo,因為如果不使用這個這個點將會在(0,0)開始,最後我們回去到xy點作為控制點,最後使用返回 真的方式讓ACTION_MOVE,ACTION_UP事件往這個控制元件繼續傳遞事件。


再來看當觸發ACTION_MOVE時,因為貝塞爾曲線是由線段構成的,結束點時線上段的中間的位置,所以這裡的計算方法是(起點+最後的點)/2就可以得到中間的點.

使用方式:

<com.campus.shopping.drawtext.finger
    android:id="@+id/viewmy"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" />