Przeglądaj źródła

Library
添加通用签名模块

Ray Zhang 7 lat temu
rodzic
commit
5a8264b379

+ 129 - 0
ApexDrivers/RAUtilsLibrary/src/main/java/com/usai/redant/rautils/signature/Bezier.java

@@ -0,0 +1,129 @@
+package com.usai.redant.rautils.signature;
+
+public class Bezier {
+    //控制点的,
+    private ControllerPoint mControl = new ControllerPoint();
+    //距离
+    private ControllerPoint mDestination = new ControllerPoint();
+    //下一个需要控制点
+    private ControllerPoint mNextControl = new ControllerPoint();
+    //资源的点
+    private ControllerPoint mSource = new ControllerPoint();
+
+    public Bezier() {
+    }
+
+    /**
+     * 初始化两个点,
+     * @param last 最后的点的信息
+     * @param cur 当前点的信息,当前点的信息,当前点的是根据事件获得,同时这个当前点的宽度是经过计算的得出的
+     */
+    public void init(ControllerPoint last, ControllerPoint cur)
+    {
+        init(last.x, last.y, last.width, cur.x, cur.y, cur.width);
+    }
+
+    public void init(float lastx, float lasty, float lastWidth, float x, float y, float width)
+    {
+        //资源点设置,最后的点的为资源点
+        mSource.set(lastx, lasty, lastWidth);
+        float xmid = getMid(lastx, x);
+        float ymid = getMid(lasty, y);
+        float wmid = getMid(lastWidth, width);
+        //距离点为平均点
+        mDestination.set(xmid, ymid, wmid);
+        //控制点为当前的距离点
+        mControl.set(getMid(lastx,xmid),getMid(lasty,ymid),getMid(lastWidth,wmid));
+        //下个控制点为当前点
+        mNextControl.set(x, y, width);
+    }
+
+    public void addNode(ControllerPoint cur){
+        addNode(cur.x, cur.y, cur.width);
+    }
+
+    /**
+     * 替换就的点,原来的距离点变换为资源点,控制点变为原来的下一个控制点,距离点取原来控制点的和新的的一半
+     * 下个控制点为新的点
+     * @param x 新的点的坐标
+     * @param y 新的点的坐标
+     * @param width
+     */
+    public void addNode(float x, float y, float width){
+        mSource.set(mDestination);
+        mControl.set(mNextControl);
+        mDestination.set(getMid(mNextControl.x, x), getMid(mNextControl.y, y), getMid(mNextControl.width, width));
+        mNextControl.set(x, y, width);
+    }
+
+    /**
+     * 结合手指抬起来的动作,告诉现在的曲线控制点也必须变化,其实在这里也不需要结合着up事件使用
+     * 因为在down的事件中,所有点都会被重置,然后设置这个没有多少意义,但是可以改变下个事件的朝向改变
+     * 先留着,因为后面如果需要控制整个颜色的改变的话,我的依靠这个方法,还有按压的时间的变化
+     */
+    public void end() {
+        mSource.set(mDestination);
+        float x = getMid(mNextControl.x, mSource.x);
+        float y = getMid(mNextControl.y, mSource.y);
+        float w = getMid(mNextControl.width, mSource.width);
+        mControl.set(x, y, w);
+        mDestination.set(mNextControl);
+    }
+
+    /**
+     *
+     * @param t 孔子
+     * @return
+     */
+    public ControllerPoint getPoint(double t){
+        float x = (float)getX(t);
+        float y = (float)getY(t);
+        float w = (float)getW(t);
+        ControllerPoint point = new ControllerPoint();
+        point.set(x,y,w);
+        return point;
+    }
+
+    /**
+     * 三阶曲线的控制点
+     * @param p0
+     * @param p1
+     * @param p2
+     * @param t
+     * @return
+     */
+    private double getValue(double p0, double p1, double p2, double t){
+        double A = p2 - 2 * p1 + p0;
+        double B = 2 * (p1 - p0);
+        double C = p0;
+        return A * t * t + B * t + C;
+    }
+
+    private double getX(double t) {
+        return getValue(mSource.x, mControl.x, mDestination.x, t);
+    }
+
+    private double getY(double t) {
+        return getValue(mSource.y, mControl.y, mDestination.y, t);
+    }
+
+    private double getW(double t){
+        return getWidth(mSource.width, mDestination.width, t);
+    }
+
+    /**
+     *
+     * @param x1 一个点的x
+     * @param x2 一个点的x
+     * @return
+     */
+    private float getMid(float x1, float x2) {
+        return (float)((x1 + x2) / 2.0);
+    }
+
+    private double getWidth(double w0, double w1, double t){
+        return w0 + (w1 - w0) * t;
+    }
+
+}
+

+ 41 - 0
ApexDrivers/RAUtilsLibrary/src/main/java/com/usai/redant/rautils/signature/ControllerPoint.java

@@ -0,0 +1,41 @@
+package com.usai.redant.rautils.signature;
+
+public class ControllerPoint{
+
+    //点信息
+
+    public int x;
+    public int y;
+
+    public float width;
+    public int alpha = 255;
+    public ControllerPoint() {
+    }
+
+    public ControllerPoint(float x, float y) {
+        this.x = (int)x;
+        this.y = (int)y;
+    }
+
+
+    public void set(float x, float y, float w) {
+        this.x = (int)x;
+        this.y = (int)y;
+        this.width = w;
+    }
+
+
+    public void set(ControllerPoint point) {
+        this.x = point.x;
+        this.y = point.y;
+        this.width = point.width;
+    }
+
+
+    public String toString() {
+        String str = "X = " + x + "; Y = " + y + "; W = " + width;
+        return str;
+    }
+
+
+}

+ 22 - 0
ApexDrivers/RAUtilsLibrary/src/main/java/com/usai/redant/rautils/signature/MotionElement.java

@@ -0,0 +1,22 @@
+package com.usai.redant.rautils.signature;
+
+public class MotionElement {
+
+    //保存从屏幕触摸事件抓取的需要的信息
+
+    public float x;
+    public float y;
+    //压力值  物理设备决定的,和设计的设备有关系,在此Demo中没有用到 ,但是这个坑  记录下
+    public float pressure;
+    //绘制的工具是否是手指或者是笔(触摸笔)
+    public int tooltype;
+
+    public MotionElement(float mx, float my, float mp, int ttype) {
+        x = mx;
+        y = my;
+        pressure = mp;
+        tooltype = ttype;
+    }
+
+
+}

+ 315 - 0
ApexDrivers/RAUtilsLibrary/src/main/java/com/usai/redant/rautils/signature/SSignatureView.java

@@ -0,0 +1,315 @@
+package com.usai.redant.rautils.signature;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.View;
+
+import java.util.ArrayList;
+
+public class SSignatureView extends SurfaceView implements SurfaceHolder.Callback ,Runnable {
+
+    private SurfaceHolder mHolder;
+
+    //画笔参数
+    public int penColor = Color.BLACK;
+    public int penWidth = 20;
+
+
+
+
+    // action 类型
+    int Touch_Action=-1;
+
+
+    private Bitmap mBitmap;//signature 位图
+    private Paint mPaint;//画笔
+    private Canvas mbmpCanvas;//画布
+
+
+//    private VelocityTracker mVelocityTracker;
+    private ArrayList<ControllerPoint> mHWPointList=new ArrayList<>();
+    ControllerPoint last_Point =null;
+    int idx_lastdraw=0;
+    int idx_lastaction = 0;
+//      SurfaceHolder.Callback shCallback = new SurfaceHolder.Callback2();
+
+    public SSignatureView(Context context) {
+        super(context);
+        init(context);
+    }
+
+    public SSignatureView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init(context);
+    }
+
+    public SSignatureView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init(context);
+    }
+
+    public SSignatureView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        init(context);
+    }
+    void init(final Context context)
+    {
+
+        post(new Runnable() {
+
+            @Override
+            public void run() {
+                Log.d("viewpost", "run: ");
+
+                mHolder = getHolder();
+//                mHolder.addCallback(this);
+//                mVelocityTracker = VelocityTracker.obtain();
+                initPaint();
+                initCanvas( context);
+
+            }
+        });
+
+    }
+    private void initPaint() {
+        mPaint = new Paint();
+        mPaint.setColor(penColor);
+        mPaint.setStrokeWidth(penWidth);
+        mPaint.setStyle(Paint.Style.STROKE);
+        mPaint.setStrokeCap(Paint.Cap.ROUND);//结束的笔画为圆心
+        mPaint.setStrokeJoin(Paint.Join.ROUND);//连接处元
+        mPaint.setAlpha(0xFF);
+        mPaint.setAntiAlias(true);
+        mPaint.setStrokeMiter(1.0f);
+//        mStokeBrushPen.setPaint(mPaint);
+    }
+
+    private void initCanvas(Context context) {
+//        DisplayMetrics dm = new DisplayMetrics();
+//        ((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(dm);
+//
+
+
+//        mBitmap = Bitmap.createBitmap(dm.widthPixels, dm.heightPixels, Bitmap.Config.ARGB_8888);
+
+
+
+        int width = View.MeasureSpec.makeMeasureSpec(0,
+                View.MeasureSpec.UNSPECIFIED);
+        int height = View.MeasureSpec.makeMeasureSpec(0,
+                View.MeasureSpec.UNSPECIFIED);
+        measure(width, height);
+
+        mBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
+        mbmpCanvas = new Canvas(mBitmap);
+        //设置画布的颜色的问题
+        mbmpCanvas.drawColor(Color.TRANSPARENT);
+
+
+        clearcavas();
+    }
+
+    void clearcavas()
+    {
+        Canvas canvas = mHolder.lockCanvas();
+        canvas.drawColor(Color.WHITE);
+        mHolder.unlockCanvasAndPost(canvas);
+
+
+
+    }
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+
+
+        long startTime = System.currentTimeMillis(); //起始时间
+
+//        mVelocityTracker.addMovement(event);
+
+//        mIsCanvasDraw = true;
+        MotionEvent event2 = MotionEvent.obtain(event);
+//        mStokeBrushPen.onTouchEvent(event2, mCanvas);
+        //event会被下一次事件重用,这里必须生成新的,否则会有问题
+        //getActionMask:触摸的动作,按下,抬起,滑动,多点按下,多点抬起
+        Touch_Action = event2.getActionMasked();
+        switch (Touch_Action) {
+            case MotionEvent.ACTION_DOWN:
+                TouchDown(createMotionElement(event2), mbmpCanvas);
+//                if (mGetTimeListner!=null)
+//                    mGetTimeListner.stopTime();
+                break;
+            case MotionEvent.ACTION_MOVE:
+                TouchMove(createMotionElement(event2), mbmpCanvas);
+//                if (mGetTimeListner!=null)
+//                    mGetTimeListner.stopTime();
+                break;
+            case MotionEvent.ACTION_UP:
+                TouchUp(createMotionElement(event2), mbmpCanvas);
+//                long time = System.currentTimeMillis();
+//                if (mGetTimeListner!=null)
+//                    mGetTimeListner.getTime(time);
+                break;
+            default:
+                break;
+        }
+
+        long endTime = System.currentTimeMillis(); //结束时间
+        long runTime = endTime - startTime;
+        Log.i("onTouchEvent", String.format("方法使用时间 %d ms", runTime));
+//        partialrefresh=true;
+        Draw();
+
+
+//        invalidate((int)event.getX()-50,(int)event.getY()-50,(int)event.getX()+50,(int)event.getY()+50);
+//        updateView(vCanvas);
+        return true;
+    }
+
+    ControllerPoint getControlPoint(MotionElement element)
+    {
+        return new ControllerPoint(element.x, element.y);
+    }
+    void TouchDown(MotionElement element, Canvas c)
+    {
+        ControllerPoint cp =  getControlPoint(element);
+        last_Point = cp;
+        idx_lastaction=mHWPointList.size();
+        mHWPointList.add(cp);
+
+    }
+    void TouchMove(MotionElement element, Canvas c)
+    {
+        ControllerPoint cp =  getControlPoint(element);
+        last_Point = cp;
+        idx_lastaction=mHWPointList.size();
+        mHWPointList.add(cp);
+    }
+    void TouchUp(MotionElement element, Canvas c)
+    {
+        ControllerPoint cp =  getControlPoint(element);
+        last_Point = cp;
+        idx_lastaction=mHWPointList.size();
+        mHWPointList.add(cp);
+    }
+    /**
+     * event.getPressure(); //LCD可以感应出用户的手指压力,当然具体的级别由驱动和物理硬件决定的,我的手机上为1
+     * @param motionEvent
+     * @return
+     */
+    private MotionElement createMotionElement(MotionEvent motionEvent) {
+
+        MotionElement motionElement = new MotionElement(motionEvent.getX(), motionEvent.getY(),
+                motionEvent.getPressure(), motionEvent.getToolType(0));
+        return motionElement;
+    }
+
+
+
+    void Draw()
+    {
+        run();
+      //  new Thread(this).start();
+
+    }
+    //implements SurfaceHolder.Callback
+    @Override
+    public void surfaceCreated(SurfaceHolder holder) {
+        clearcavas();
+    }
+
+    @Override
+    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+
+    }
+
+    @Override
+    public void surfaceDestroyed(SurfaceHolder holder) {
+
+    }
+
+    @Override
+    public void run() {
+        Canvas canvas = mHolder.lockCanvas();
+        if (canvas != null) {
+            try {
+//                mCanvas.drawRect(mCanvas.getClipBounds(),mPaint);
+                //使用获得的Canvas做具体的绘制
+
+                long startTime = System.currentTimeMillis(); //起始时间
+
+                canvas.drawColor(Color.WHITE);
+                canvas.drawBitmap(mBitmap, 0, 0, mPaint);
+
+                ControllerPoint start = null;
+                ControllerPoint end = null;
+                if(mHWPointList.size()>0)
+                {
+                    start = mHWPointList.get(idx_lastdraw);
+
+                    end = mHWPointList.get(idx_lastaction);
+                }
+                switch (Touch_Action) {
+                    case MotionEvent.ACTION_DOWN:
+                        Log.d("ACTION_DOWN", "ACTION_DOWN");
+                        if(end!=null) {
+                            mbmpCanvas.drawPoint(end.x, end.y, mPaint);
+                            idx_lastdraw = idx_lastaction;
+//                if (mGetTimeListner!=null)
+//                    mGetTimeListner.stopTime();
+                        }
+                        else
+                        {
+                            Log.d("ACTION_DOWN", "onDraw: end is null");
+                        }
+                        break;
+                    case MotionEvent.ACTION_MOVE:
+                        Log.d("ACTION_MOVE", "ACTION_MOVE");
+                        if(start!=null&& end!=null)
+                        {
+                            mbmpCanvas.drawLine(start.x,start.y,end.x,end.y,mPaint);
+                            idx_lastdraw=idx_lastaction;
+
+                        }
+                        else
+                        {
+                            Log.d("ACTION_MOVE", "onDraw: "+(start==null)+(end==null));
+                        }
+
+//                if (mGetTimeListner!=null)
+//                    mGetTimeListner.stopTime();
+                        break;
+                    case MotionEvent.ACTION_UP:
+                        Log.d("ACTION_UP", "ACTION_UP");
+                        idx_lastdraw=idx_lastaction;
+//                mbmpCanvas.drawLine(start.x,start.y,end.x,end.y,mPaint);
+//                long time = System.currentTimeMillis();
+//                if (mGetTimeListner!=null)
+//                    mGetTimeListner.getTime(time);
+                        break;
+                    default:
+                        Log.d("OTHER_ACTION", "CODE: "+Touch_Action);
+                        break;
+                }
+
+
+                long endTime = System.currentTimeMillis(); //结束时间
+                long runTime = endTime - startTime;
+                Log.i("绘制", String.format("方法使用时间 %d ms", runTime)+"++++++++++++ code");
+
+
+            } catch (Exception e) {
+                e.printStackTrace();
+            } finally {
+                mHolder.unlockCanvasAndPost(canvas);
+            }
+        }
+    }
+}

+ 649 - 0
ApexDrivers/RAUtilsLibrary/src/main/java/com/usai/redant/rautils/signature/SignatureView.java

@@ -0,0 +1,649 @@
+package com.usai.redant.rautils.signature;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.RectF;
+import android.support.annotation.Nullable;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+
+import java.util.ArrayList;
+
+public class SignatureView extends View {
+
+
+    //画笔参数
+    public int penColor = Color.BLACK;//笔的颜色
+    public int penWidth = 25;//设置笔的宽度
+
+    public double DIS_VEL_CAL_FACTOR = 0.01f;//这个控制笔锋的控制值
+
+    //手指在移动的控制笔的变化率  这个值越大,线条的粗细越加明显
+    //float WIDTH_THRES_MAX = 0.6f;
+    float WIDTH_THRES_MAX = 0.6f;
+
+    //计算线宽
+    public double mLastVel;
+
+    public double mLastWidth;
+
+    //线平滑
+    public Bezier mBezier = new Bezier();
+    //绘制计算的次数,数值越小计算的次数越多,需要折中
+    int STEPFACTOR = 10;
+
+    int Touch_Action=-1;
+
+    private Bitmap mBitmap;
+    private Paint mPaint;//画笔
+    private Canvas mbmpCanvas;//画布
+
+    int idx_drawstart=0;
+    int idx_drawend=0;
+//    private VelocityTracker mVelocityTracker;
+
+    private ArrayList<ControllerPoint> mMeasurePointList=new ArrayList<>();
+
+    private ArrayList<ControllerPoint> mComputePointList=new ArrayList<>();
+
+    private ControllerPoint   mLastPoint = new ControllerPoint(0, 0);
+    private ControllerPoint mCurPoint;
+
+//    ControllerPoint last_Point =null;
+    int idx_lastdraw=0;
+    int idx_lastaction = 0;
+    public SignatureView(Context context) {
+        super(context);
+        init(context);
+    }
+
+    public SignatureView(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+        init(context);
+    }
+
+    public SignatureView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init(context);
+    }
+
+    public SignatureView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        init(context);
+    }
+    @Override
+    protected void finalize() throws Throwable
+    {
+//        mVelocityTracker.recycle();
+        super.finalize();
+
+        // other finalization code...
+
+    }
+
+    void init(final Context context)
+    {
+
+        post(new Runnable() {
+
+            @Override
+            public void run() {
+                Log.d("viewpost", "run: ");
+//                mVelocityTracker = VelocityTracker.obtain();
+                initPaint();
+                initCanvas( context);
+                Log.d("viewpost", "init done ");
+            }
+        });
+
+    }
+
+    private void initPaint() {
+        mPaint = new Paint();
+        mPaint.setColor(penColor);
+        mPaint.setStrokeWidth(penWidth);
+        mPaint.setStyle(Paint.Style.FILL);
+        mPaint.setStrokeCap(Paint.Cap.ROUND);//结束的笔画为圆心
+        mPaint.setStrokeJoin(Paint.Join.ROUND);//连接处元
+        mPaint.setAlpha(0xFF);
+        mPaint.setAntiAlias(true);
+        mPaint.setStrokeMiter(1.0f);
+//        mStokeBrushPen.setPaint(mPaint);
+    }
+
+    private void initCanvas(Context context) {
+        DisplayMetrics dm = new DisplayMetrics();
+        ((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(dm);
+
+
+
+//        mBitmap = Bitmap.createBitmap(dm.widthPixels, dm.heightPixels, Bitmap.Config.ARGB_8888);
+
+
+
+        int width = View.MeasureSpec.makeMeasureSpec(0,
+                View.MeasureSpec.UNSPECIFIED);
+        int height = View.MeasureSpec.makeMeasureSpec(0,
+                View.MeasureSpec.UNSPECIFIED);
+        measure(width, height);
+
+        mBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
+        mbmpCanvas = new Canvas(mBitmap);
+        //设置画布的颜色的问题
+        mbmpCanvas.drawColor(Color.TRANSPARENT);
+    }
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+
+
+        long startTime = System.currentTimeMillis(); //起始时间
+
+//        mVelocityTracker.addMovement(event);
+
+//        mIsCanvasDraw = true;
+        MotionEvent event2 = MotionEvent.obtain(event);
+//        mStokeBrushPen.onTouchEvent(event2, mCanvas);
+        //event会被下一次事件重用,这里必须生成新的,否则会有问题
+        //getActionMask:触摸的动作,按下,抬起,滑动,多点按下,多点抬起
+        Touch_Action = event2.getActionMasked();
+        switch (Touch_Action) {
+            case MotionEvent.ACTION_DOWN:
+                TouchDown(createMotionElement(event2), mbmpCanvas);
+//                if (mGetTimeListner!=null)
+//                    mGetTimeListner.stopTime();
+                break;
+            case MotionEvent.ACTION_MOVE:
+
+                Log.d("move", "onTouchEvent: move "+event.getX()+" , "+event.getY());
+//                Bezier bezier = new Bezier(lastPoint, newPoint);
+                TouchMove(createMotionElement(event2), mbmpCanvas);
+//                if (mGetTimeListner!=null)
+//                    mGetTimeListner.stopTime();
+                break;
+            case MotionEvent.ACTION_UP:
+                TouchUp(createMotionElement(event2), mbmpCanvas);
+//                long time = System.currentTimeMillis();
+//                if (mGetTimeListner!=null)
+//                    mGetTimeListner.getTime(time);
+                break;
+            default:
+
+                Log.i("onTouchEvent", "OTHER ACTION "+Touch_Action);
+                break;
+        }
+
+        long endTime = System.currentTimeMillis(); //结束时间
+        long runTime = endTime - startTime;
+        Log.i("onTouchEvent", String.format("方法使用时间 %d ms", runTime));
+//        partialrefresh=true;
+        invalidate();
+
+
+//        invalidate((int)event.getX()-50,(int)event.getY()-50,(int)event.getX()+50,(int)event.getY()+50);
+//        updateView(vCanvas);
+        return true;
+    }
+
+    ControllerPoint getControlPoint(MotionElement element)
+    {
+        return new ControllerPoint(element.x, element.y);
+    }
+    void TouchDown(MotionElement element, Canvas c)
+    {
+        ControllerPoint cp =  getControlPoint(element);
+//        last_Point = cp;
+        idx_lastaction=mMeasurePointList.size();
+//        mMeasurePointList.add(cp);
+
+
+
+        if (mPaint==null){
+            throw new NullPointerException("paint 笔不可能为null哦");
+        }
+//        if (getNewPaint(mPaint)!=null){
+//            Paint paint=getNewPaint(mPaint);
+//            mPaint=paint;
+//            //当然了,不要因为担心内存泄漏,在每个变量使用完成后都添加xxx=null,
+//            // 对于消除过期引用的最好方法,就是让包含该引用的变量结束生命周期,而不是显示的清空
+//            paint=null;
+//            System.out.println("shiming 当绘制的时候是否为新的paint"+mPaint+"原来的对象是否销毁了paint=="+paint);
+//        }
+        mMeasurePointList.clear();
+        //如果在brush字体这里接受到down的事件,把下面的这个集合清空的话,那么绘制的内容会发生改变
+        //不清空的话,也不可能
+        mComputePointList.clear();
+        //记录down的控制点的信息
+        ControllerPoint curPoint = new ControllerPoint(element.x, element.y);
+        //如果用笔画的画我的屏幕,记录他宽度的和压力值的乘,但是哇,
+        if (element.tooltype == MotionEvent.TOOL_TYPE_STYLUS) {
+            mLastWidth = element.pressure * penWidth;
+        } else {
+            //如果是手指画的,我们取他的0.8
+            mLastWidth = 0.8 * penWidth;
+        }
+        //down下的点的宽度
+        curPoint.width = (float) mLastWidth;
+        mLastVel = 0;
+        mMeasurePointList.add(curPoint);
+        //记录当前的点
+        mLastPoint = curPoint;
+    }
+    void TouchMove(MotionElement element, Canvas c)
+    {
+//        ControllerPoint cp =  getControlPoint(element);
+//        last_Point = cp;
+        idx_lastaction=mMeasurePointList.size();
+//        mMeasurePointList.add(cp);
+
+
+
+
+
+
+        ControllerPoint curPoint = new ControllerPoint(element.x, element.y);
+
+        if(mMeasurePointList.size()>0)
+        {
+            ControllerPoint lp=mMeasurePointList.get(mMeasurePointList.size()-1);
+            if(lp.x==curPoint.x&& lp.y==curPoint.y)
+                return;
+        }
+
+        double deltaX = curPoint.x - mLastPoint.x;
+        double deltaY = curPoint.y - mLastPoint.y;
+        //deltaX和deltay平方和的二次方根 想象一个例子 1+1的平方根为1.4 (x²+y²)开根号
+        //同理,当滑动的越快的话,deltaX+deltaY的值越大,这个越大的话,curDis也越大
+        double curDis = Math.hypot(deltaX, deltaY);
+        //我们求出的这个值越小,画的点或者是绘制椭圆形越多,这个值越大的话,绘制的越少,笔就越细,宽度越小
+        double curVel = curDis * DIS_VEL_CAL_FACTOR;
+        double curWidth;
+        //点的集合少,我们得必须改变宽度,每次点击的down的时候,这个事件
+        if (mMeasurePointList.size() < 2) {
+            if (element.tooltype == MotionEvent.TOOL_TYPE_STYLUS) {
+                curWidth = element.pressure * penWidth;
+            } else {
+                curWidth = calcNewWidth(curVel, mLastVel, curDis, 1.5,
+                        mLastWidth);
+            }
+            curPoint.width = (float) curWidth;
+            mBezier.init(mLastPoint, curPoint);
+        } else {
+            mLastVel = curVel;
+            if (element.tooltype == MotionEvent.TOOL_TYPE_STYLUS) {
+                curWidth = element.pressure * penWidth;
+            } else {
+                //由于我们手机是触屏的手机,滑动的速度也不慢,所以,一般会走到这里来
+                //阐明一点,当滑动的速度很快的时候,这个值就越小,越慢就越大,依靠着mlastWidth不断的变换
+                curWidth = calcNewWidth(curVel, mLastVel, curDis, 1.5,
+                        mLastWidth);
+            }
+            curPoint.width = (float) curWidth;
+            Log.i("onTouchEvent", "move width"+curWidth);
+            mBezier.addNode(curPoint);
+        }
+        //每次移动的话,这里赋值新的值
+        mLastWidth = curWidth;
+        mMeasurePointList.add(curPoint);
+        moveNeetToDo(curDis);
+        mLastPoint = curPoint;
+    }
+    void TouchUp(MotionElement element, Canvas c)
+    {
+        ControllerPoint cp =  getControlPoint(element);
+//        last_Point = cp;
+        idx_lastaction=mMeasurePointList.size();
+//        mMeasurePointList.add(cp);
+
+
+
+
+        mCurPoint = new ControllerPoint(element.x, element.y);
+        double deltaX = mCurPoint.x - mLastPoint.x;
+        double deltaY = mCurPoint.y - mLastPoint.y;
+        double curDis = Math.hypot(deltaX, deltaY);
+        //如果用笔画的画我的屏幕,记录他宽度的和压力值的乘,但是哇,这个是不会变的
+        if (element.tooltype == MotionEvent.TOOL_TYPE_STYLUS) {
+            mCurPoint.width = (float) (element.pressure * penWidth);
+        } else {
+            mCurPoint.width = 0;
+        }
+
+        mMeasurePointList.add(mCurPoint);
+
+        mBezier.addNode(mCurPoint);
+
+        int steps = 1 + (int) curDis / STEPFACTOR;
+        double step = 1.0 / steps;
+        for (double t = 0; t < 1.0; t += step) {
+            ControllerPoint point = mBezier.getPoint(t);
+            mComputePointList.add(point);
+        }
+        //
+        mBezier.end();
+        for (double t = 0; t < 1.0; t += step) {
+            ControllerPoint point = mBezier.getPoint(t);
+            mComputePointList.add(point);
+        }
+
+        // 手指up 我画到纸上上
+//        draw(canvas);
+        //每次抬起手来,就把集合清空,在水彩笔的那个地方,如果啊,我说如果不清空的话,每次抬起手来,
+        // 在onDown下去的话,最近画的线的透明度有改变,所以这里clear下线的集合
+        clear();
+    }
+
+    public void clear() {
+        mComputePointList.clear();
+        mMeasurePointList.clear();
+        idx_drawstart=0;
+        idx_drawend=0;
+    }
+
+
+    /**
+     * 清除画布,记得清除点的集合
+     */
+    public void reset() {
+        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
+        mbmpCanvas.drawPaint(mPaint);
+        mPaint.setXfermode(null);
+        clear();
+
+    }
+    /**
+     * event.getPressure(); //LCD可以感应出用户的手指压力,当然具体的级别由驱动和物理硬件决定的,我的手机上为1
+     * @param motionEvent
+     * @return
+     */
+    private MotionElement createMotionElement(MotionEvent motionEvent) {
+
+        MotionElement motionElement = new MotionElement(motionEvent.getX(), motionEvent.getY(),
+                motionEvent.getPressure(), motionEvent.getToolType(0));
+        return motionElement;
+    }
+
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+
+
+//        Rect r=canvas.getClipBounds();
+//        vCanvas = canvas;
+        long startTime = System.currentTimeMillis(); //起始时间
+
+
+        ControllerPoint start = null;
+        ControllerPoint end = null;
+//        if(mHWPointList.size()>0)
+//        {
+//            start = mHWPointList.get(idx_lastdraw);
+//
+//            end = mHWPointList.get(idx_lastaction);
+//        }
+
+        if(mComputePointList.size()>0)
+        {
+            start=mComputePointList.get(idx_drawstart);
+            end=mComputePointList.get(idx_drawend);
+        }
+
+        switch (Touch_Action) {
+            case MotionEvent.ACTION_DOWN:
+                if(end!=null) {
+                    idx_lastdraw = idx_lastaction;
+                    mbmpCanvas.drawPoint(end.x, end.y, mPaint);
+
+                    idx_drawstart = idx_drawend;
+//                if (mGetTimeListner!=null)
+//                    mGetTimeListner.stopTime();
+                }
+                else
+                {
+                    Log.d("ACTION_DOWN", "onDraw: end is null");
+                }
+                break;
+            case MotionEvent.ACTION_MOVE:
+                if(start!=null&& end!=null)
+                {
+                    idx_lastdraw=idx_lastaction;
+//                    mbmpCanvas.drawLine(start.x,start.y,end.x,end.y,mPaint);
+
+
+                    for(int i=idx_drawstart;i<idx_drawend;i++)
+//                    for(int i=0;i<mComputePointList.size()-1;i++)
+                    {
+//                        mbmpCanvas.drawLine(mComputePointList.get(i).x,mComputePointList.get(i).y,mComputePointList.get(i+1).x,mComputePointList.get(i+1).y,mPaint);
+
+                        drawLine(mbmpCanvas,mComputePointList.get(i).x,mComputePointList.get(i).y,mComputePointList.get(i).width,mComputePointList.get(i+1).x,mComputePointList.get(i+1).y,mComputePointList.get(i+1).width,mPaint);
+                    }
+
+                    Log.d("ACTION_MOVE", "onDraw: "+idx_drawstart+"------"+idx_drawend+"....."+mComputePointList.size());
+                    idx_drawstart = idx_drawend;
+                }
+                else
+                {
+                    Log.d("ACTION_MOVE", "onDraw: "+(start==null)+(end==null));
+                }
+
+//                if (mGetTimeListner!=null)
+//                    mGetTimeListner.stopTime();
+                break;
+            case MotionEvent.ACTION_UP:
+                idx_lastdraw=idx_lastaction;
+//                mbmpCanvas.drawLine(start.x,start.y,end.x,end.y,mPaint);
+//                long time = System.currentTimeMillis();
+//                if (mGetTimeListner!=null)
+//                    mGetTimeListner.getTime(time);
+                break;
+            default:
+                idx_lastdraw=idx_lastaction;
+                break;
+        }
+        canvas.drawBitmap(mBitmap, 0, 0, mPaint);
+        super.onDraw(canvas);
+        long endTime = System.currentTimeMillis(); //结束时间
+        long runTime = endTime - startTime;
+        Log.i("绘制", String.format("方法使用时间 %d ms", runTime)+"++++++++++++ ");
+    }
+
+
+
+    //各种计算
+
+    //计算宽度
+    public double calcNewWidth(double curVel, double lastVel, double curDis,
+                               double factor, double lastWidth) {
+        double calVel = curVel * 0.6 + lastVel * (1 - 0.6);
+        //返回指定数字的自然对数
+        //手指滑动的越快,这个值越小,为负数
+        double vfac = Math.log(factor * 2.0f) * (-calVel);
+        //此方法返回值e,其中e是自然对数的基数。
+        //Math.exp(vfac) 变化范围为0 到1 当手指没有滑动的时候 这个值为1 当滑动很快的时候无线趋近于0
+        //在次说明下,当手指抬起来,这个值会变大,这也就说明,抬起手太慢的话,笔锋效果不太明显
+        //这就说明为什么笔锋的效果不太明显
+        double calWidth = penWidth * Math.exp(vfac);
+
+        //滑动的速度越快的话,mMoveThres也越大
+        double mMoveThres = curDis * 0.01f;
+        //对之值最大的地方进行控制
+        if (mMoveThres > WIDTH_THRES_MAX) {
+            mMoveThres = WIDTH_THRES_MAX;
+        }
+        // TODO: 2018/2/24   以下的方法 可以删除掉  原因是抽取了一下 ,本来不应该在这里的出现的  不好意思
+//        //滑动越慢的情况下,得到的calWidth 和上面的calwidth 相差的值不一样
+//
+//        //滑动的越快的话,第一个判断会走
+//        if (Math.abs(calWidth - mBaseWidth) / mBaseWidth > mMoveThres) {
+//            if (calWidth > mBaseWidth) {
+//                calWidth = mBaseWidth * (1 + mMoveThres);
+//            } else {
+//                calWidth = mBaseWidth * (1 - mMoveThres);
+//            }
+//            //滑动的越慢的话,第二个判断会走  基本上在屏幕上手指基本上没有走动的时候 ,就会走这个方法
+//        } else if (Math.abs(calWidth - lastWidth) / lastWidth > mMoveThres) {
+//            if (calWidth > lastWidth) {
+//                calWidth = lastWidth * (1 + mMoveThres);
+//            } else {
+//                calWidth = lastWidth * (1 - mMoveThres);
+//            }
+//        }
+        return calWidth;
+    }
+// 生成计算点(贝塞尔曲线)
+    protected void moveNeetToDo(double curDis) {
+        int steps = 1 + (int) curDis / STEPFACTOR;
+        Log.d("pen debug", "steps "+steps);
+        if(steps==1)
+            steps=1;
+        double step = 1.0 / steps;
+//        idx_drawstart = mComputePointList.size()-1;
+//        if(idx_drawstart<0)
+//            idx_drawstart = 0;
+        for (double t = 0; t < 1.0; t += step) {
+            ControllerPoint point = mBezier.getPoint(t);
+            //过滤坐标重复的点
+            if(mComputePointList.size()>0)
+            {
+                ControllerPoint last = mComputePointList.get(mComputePointList.size()-1);
+                if(last.x==point.x&&last.y==point.y)
+                    continue;
+            }
+            Log.d("pen debug", "Compute Point width "+point.width);
+            mComputePointList.add(point);
+        }
+
+        idx_drawend = mComputePointList.size()-1;
+
+//        Log.d("pen debug", "size() "+mComputePointList.size()+",,,"+(idx_drawend-idx_drawstart));
+    }
+
+
+    private void drawLine(Canvas canvas, double x0, double y0, double w0, double x1, double y1, double w1, Paint paint) {
+        //求两个数字的平方根 x的平方+y的平方在开方记得X的平方+y的平方=1,这就是一个园
+        double curDis = Math.hypot(x0 - x1, y0 - y1);
+        int steps = 1;
+        if (paint.getStrokeWidth() < 6) {
+            steps = 1 + (int) (curDis / 2);
+        } else if (paint.getStrokeWidth() > 60) {
+            steps = 1 + (int) (curDis / 4);
+        } else {
+            steps = 1 + (int) (curDis / 3);
+        }
+        double deltaX = (x1 - x0) / steps;
+        double deltaY = (y1 - y0) / steps;
+        double deltaW = (w1 - w0) / steps;
+        double x = x0;
+        double y = y0;
+        double w = w0;
+
+        Log.d("drawLine","line width "+w+","+w0+","+deltaW);
+        for (int i = 0; i < steps; i++) {
+            //都是用于表示坐标系中的一块矩形区域,并可以对其做一些简单操作
+            //精度不一样。Rect是使用int类型作为数值,RectF是使用float类型作为数值。
+            //            Rect rect = new Rect();
+            RectF oval = new RectF();
+            oval.set((float) (x - w / 4.0f), (float) (y - w / 2.0f), (float) (x + w / 4.0f), (float) (y + w / 2.0f));
+            // oval.set((float)(x+w/4.0f), (float)(y+w/4.0f), (float)(x-w/4.0f), (float)(y-w/4.0f));
+            //最基本的实现,通过点控制线,绘制椭圆
+            canvas.drawOval(oval, paint);
+            x += deltaX;
+            y += deltaY;
+            w += deltaW;
+        }
+    }
+
+
+    private int mBackColor = Color.TRANSPARENT;
+    /**
+     * 逐行扫描 清楚边界空白。功能是生成一张bitmap位于正中间,不是位于顶部,此关键的是我们画布需要
+     * 成透明色才能生效
+     * @param blank 边距留多少个像素
+     * @return tks github E-signature
+     */
+    public Bitmap clearBlank(int blank) {
+        if (mBitmap != null) {
+            int HEIGHT = mBitmap.getHeight();//1794
+            int WIDTH = mBitmap.getWidth();//1080
+            int top = 0, left = 0, right = 0, bottom = 0;
+            int[] pixs = new int[WIDTH];
+            boolean isStop;
+            for (int y = 0; y < HEIGHT; y++) {
+                mBitmap.getPixels(pixs, 0, WIDTH, 0, y, WIDTH, 1);
+                isStop = false;
+                for (int pix : pixs) {
+                    if (pix != mBackColor) {
+
+                        top = y;
+                        isStop = true;
+                        break;
+                    }
+                }
+                if (isStop) {
+                    break;
+                }
+            }
+            for (int y = HEIGHT - 1; y >= 0; y--) {
+                mBitmap.getPixels(pixs, 0, WIDTH, 0, y, WIDTH, 1);
+                isStop = false;
+                for (int pix : pixs) {
+                    if (pix != mBackColor) {
+                        bottom = y;
+                        isStop = true;
+                        break;
+                    }
+                }
+                if (isStop) {
+                    break;
+                }
+            }
+            pixs = new int[HEIGHT];
+            for (int x = 0; x < WIDTH; x++) {
+                mBitmap.getPixels(pixs, 0, 1, x, 0, 1, HEIGHT);
+                isStop = false;
+                for (int pix : pixs) {
+                    if (pix != mBackColor) {
+                        left = x;
+                        isStop = true;
+                        break;
+                    }
+                }
+                if (isStop) {
+                    break;
+                }
+            }
+            for (int x = WIDTH - 1; x > 0; x--) {
+                mBitmap.getPixels(pixs, 0, 1, x, 0, 1, HEIGHT);
+                isStop = false;
+                for (int pix : pixs) {
+                    if (pix != mBackColor) {
+                        right = x;
+                        isStop = true;
+                        break;
+                    }
+                }
+                if (isStop) {
+                    break;
+                }
+            }
+            if (blank < 0) {
+                blank = 0;
+            }
+            left = left - blank > 0 ? left - blank : 0;
+            top = top - blank > 0 ? top - blank : 0;
+            right = right + blank > WIDTH - 1 ? WIDTH - 1 : right + blank;
+            bottom = bottom + blank > HEIGHT - 1 ? HEIGHT - 1 : bottom + blank;
+            return Bitmap.createBitmap(mBitmap, left, top, right - left, bottom - top);
+        } else {
+            return null;
+        }
+    }
+}

+ 12 - 11
ApexDrivers/apexdriverslib/apexdriverslib.iml

@@ -111,29 +111,30 @@
     </content>
     <orderEntry type="jdk" jdkName="Android API 26 Platform" jdkType="Android SDK" />
     <orderEntry type="sourceFolder" forTests="false" />
-    <orderEntry type="library" name="Gradle: com.google.android.gms:play-services-base-16.0.1" level="project" />
-    <orderEntry type="library" name="Gradle: com.android.support:recyclerview-v7-26.1.0" level="project" />
     <orderEntry type="library" name="Gradle: com.android.support:animated-vector-drawable-26.1.0" level="project" />
     <orderEntry type="library" name="Gradle: com.google.android.gms:play-services-tasks-16.0.1" level="project" />
-    <orderEntry type="library" name="Gradle: com.google.android.gms:play-services-places-placereport-16.0.0" level="project" />
-    <orderEntry type="library" name="Gradle: android.arch.lifecycle:common:1.0.0@jar" level="project" />
-    <orderEntry type="library" name="Gradle: com.android.support:support-vector-drawable-26.1.0" level="project" />
-    <orderEntry type="library" name="Gradle: com.android.support:support-core-ui-26.1.0" level="project" />
-    <orderEntry type="library" name="Gradle: __local_aars__:/Users/ray/Documents/code_ERPSuiteAndroid/ApexDrivers/apexdriverslib/libs/core-2.3.0.jar:unspecified@jar" level="project" />
     <orderEntry type="library" name="Gradle: com.android.support:transition-26.1.0" level="project" />
-    <orderEntry type="library" name="Gradle: com.android.support:support-core-utils-26.1.0" level="project" />
-    <orderEntry type="library" name="Gradle: com.android.support.constraint:constraint-layout-solver:1.1.2@jar" level="project" />
     <orderEntry type="library" name="Gradle: com.android.support:appcompat-v7-26.1.0" level="project" />
     <orderEntry type="library" name="Gradle: com.android.support:support-fragment-26.1.0" level="project" />
     <orderEntry type="library" name="Gradle: android.arch.core:common:1.0.0@jar" level="project" />
+    <orderEntry type="library" name="Gradle: com.googlecode.libphonenumber:libphonenumber:7.0.4@jar" level="project" />
     <orderEntry type="library" name="Gradle: com.google.android.gms:play-services-basement-16.0.1" level="project" />
     <orderEntry type="library" name="Gradle: com.android.support.constraint:constraint-layout-1.1.2" level="project" />
-    <orderEntry type="library" name="Gradle: com.google.android.gms:play-services-location-16.0.0" level="project" />
     <orderEntry type="library" name="Gradle: com.android.support:support-media-compat-26.1.0" level="project" />
     <orderEntry type="library" name="Gradle: com.android.support:support-annotations:26.1.0@jar" level="project" />
-    <orderEntry type="library" name="Gradle: com.android.support:design-26.1.0" level="project" />
     <orderEntry type="library" name="Gradle: com.android.support:support-v4-26.1.0" level="project" />
     <orderEntry type="library" name="Gradle: com.android.support:support-compat-26.1.0" level="project" />
+    <orderEntry type="library" name="Gradle: com.google.android.gms:play-services-base-16.0.1" level="project" />
+    <orderEntry type="library" name="Gradle: com.android.support:recyclerview-v7-26.1.0" level="project" />
+    <orderEntry type="library" name="Gradle: com.google.android.gms:play-services-places-placereport-16.0.0" level="project" />
+    <orderEntry type="library" name="Gradle: android.arch.lifecycle:common:1.0.0@jar" level="project" />
+    <orderEntry type="library" name="Gradle: com.android.support:support-vector-drawable-26.1.0" level="project" />
+    <orderEntry type="library" name="Gradle: com.android.support:support-core-ui-26.1.0" level="project" />
+    <orderEntry type="library" name="Gradle: __local_aars__:/Users/ray/Documents/code_ERPSuiteAndroid/ApexDrivers/apexdriverslib/libs/core-2.3.0.jar:unspecified@jar" level="project" />
+    <orderEntry type="library" name="Gradle: com.android.support:support-core-utils-26.1.0" level="project" />
+    <orderEntry type="library" name="Gradle: com.android.support.constraint:constraint-layout-solver:1.1.2@jar" level="project" />
+    <orderEntry type="library" name="Gradle: com.google.android.gms:play-services-location-16.0.0" level="project" />
+    <orderEntry type="library" name="Gradle: com.android.support:design-26.1.0" level="project" />
     <orderEntry type="library" name="Gradle: android.arch.lifecycle:runtime-1.0.0" level="project" />
     <orderEntry type="module" module-name="RAUtilsLibrary" />
   </component>