平滑的手写签名View

来源:互联网 发布:jenkins windows 编辑:程序博客网 时间:2024/05/17 09:38

无意中看到了square的一位android工程师写的自定义签名View,链接:https://corner.squareup.com/2010/07/smooth-signatures.html  ;

阅读完以后了解到:      


Android 对点击事件是批处理的,所以系统在每次调用onTouchEvent() 的时候,MotionEvent 里面都包含了坐标位置的历史记录

要想绘制平滑的签名,需要用到下面的几个方法


getHistorySize()    //  仅使用于两个 ACTION_MOVE事件之间 ,其它触摸事件返回值为0
getHistoricalX(int)   //   根据size  可以获取每个点的X值
getHistoricalY(int)   //   根据size  可以获取每个点的y值

 这样用path把所有的 坐标串联起来, 就可以绘制平滑的签名了;


//  ================================ 一般的效果以及代码========================================

士大夫


public class SignatureView extends View {  private Paint paint = new Paint();  private Path path = new Path();  public SignatureView(Context context, AttributeSet attrs) {    super(context, attrs);    paint.setAntiAlias(true);    paint.setColor(Color.BLACK);    paint.setStyle(Paint.Style.STROKE);    paint.setStrokeJoin(Paint.Join.ROUND);    paint.setStrokeWidth(5f);  }  @Override  protected void onDraw(Canvas canvas) {    canvas.drawPath(path, paint);  }  @Override  public boolean onTouchEvent(MotionEvent event) {    float eventX = event.getX();    float eventY = event.getY();    switch (event.getAction()) {      case MotionEvent.ACTION_DOWN:        path.moveTo(eventX, eventY);        return true;      case MotionEvent.ACTION_MOVE:      case MotionEvent.ACTION_UP:        path.lineTo(eventX, eventY);        break;      default:        return false;    }    // Schedules a repaint.    invalidate();    return true;  }}


//  ================================ 最终的效果以及完全代码========================================



public class SignatureView extends View {  private static final float STROKE_WIDTH = 5f;  /** Need to track this so the dirty region can accommodate the stroke. **/  private static final float HALF_STROKE_WIDTH = STROKE_WIDTH / 2;  private Paint paint = new Paint();  private Path path = new Path();  /**   * Optimizes painting by invalidating the smallest possible area.   */  private float lastTouchX;  private float lastTouchY;  private final RectF dirtyRect = new RectF();  public SignatureView(Context context, AttributeSet attrs) {    super(context, attrs);    paint.setAntiAlias(true);    paint.setColor(Color.BLACK);    paint.setStyle(Paint.Style.STROKE);    paint.setStrokeJoin(Paint.Join.ROUND);    paint.setStrokeWidth(STROKE_WIDTH);  }  /**   * Erases the signature.   */  public void clear() {    path.reset();    // Repaints the entire view.    invalidate();  }  @Override  protected void onDraw(Canvas canvas) {    canvas.drawPath(path, paint);  }  @Override  public boolean onTouchEvent(MotionEvent event) {    float eventX = event.getX();    float eventY = event.getY();    switch (event.getAction()) {      case MotionEvent.ACTION_DOWN:        path.moveTo(eventX, eventY);        lastTouchX = eventX;        lastTouchY = eventY;        // There is no end point yet, so don't waste cycles invalidating.        return true;      case MotionEvent.ACTION_MOVE:      case MotionEvent.ACTION_UP:        // Start tracking the dirty region.        resetDirtyRect(eventX, eventY);        // When the hardware tracks events faster than they are delivered, the        // event will contain a history of those skipped points.        int historySize = event.getHistorySize();        for (int i = 0; i < historySize; i++) {          float historicalX = event.getHistoricalX(i);          float historicalY = event.getHistoricalY(i);          expandDirtyRect(historicalX, historicalY);          path.lineTo(historicalX, historicalY);        }        // After replaying history, connect the line to the touch point.        path.lineTo(eventX, eventY);        break;      default:        debug("Ignored touch event: " + event.toString());        return false;    }    // Include half the stroke width to avoid clipping.    invalidate(        (int) (dirtyRect.left - HALF_STROKE_WIDTH),        (int) (dirtyRect.top - HALF_STROKE_WIDTH),        (int) (dirtyRect.right + HALF_STROKE_WIDTH),        (int) (dirtyRect.bottom + HALF_STROKE_WIDTH));    lastTouchX = eventX;    lastTouchY = eventY;    return true;  }  /**   * Called when replaying history to ensure the dirty region includes all   * points.   */  private void expandDirtyRect(float historicalX, float historicalY) {    if (historicalX < dirtyRect.left) {      dirtyRect.left = historicalX;    } else if (historicalX > dirtyRect.right) {      dirtyRect.right = historicalX;    }    if (historicalY < dirtyRect.top) {      dirtyRect.top = historicalY;    } else if (historicalY > dirtyRect.bottom) {      dirtyRect.bottom = historicalY;    }  }  /**   * Resets the dirty region when the motion event occurs.   */  private void resetDirtyRect(float eventX, float eventY) {    // The lastTouchX and lastTouchY were set when the ACTION_DOWN    // motion event occurred.    dirtyRect.left = Math.min(lastTouchX, eventX);    dirtyRect.right = Math.max(lastTouchX, eventX);    dirtyRect.top = Math.min(lastTouchY, eventY);    dirtyRect.bottom = Math.max(lastTouchY, eventY);  }}


0 0
原创粉丝点击