Join FlipAndroid.COM Telegram Group: https://t.me/joinchat/F_aqThGkhwcLzmI49vKAiw


Android: firma digital con Bezier

Introduzca aquí la descripción de la imagen
Estoy tratando de dos dibujar la firma digital con Bezier como mostrar en la imagen anterior. Cuando toco y tratar de dibujar línea, entonces el resultado es la línea de puntos, pero no obtener la línea continua. Firma simple hecho usando la firma simple pero quiero crear más una curva lisa usando Bezier con la presión del tacto. Probado con este enlace

SignatureViewDemo.java

public class SignatureViewDemo extends View { private int color = Color.BLACK; private Bitmap m_Bitmap; private final Paint m_BorderPaint; private Canvas m_Canvas; private Point m_CropBotRight; private Point m_CropTopLeft; private float m_CurrentX; private float m_CurrentY; private final float m_DesiredDash; private float m_LastWidth = 6.5F; private Paint m_PenPaint; private int m_PointIndex = 0; private ArrayList<Point> m_Points = new ArrayList<Point>(); private final float m_StrokeWidth; boolean m_Empty; public SignatureViewDemo(Context paramContext) { this(paramContext, null); } public SignatureViewDemo(Context paramContext, AttributeSet paramAttributeSet) { this(paramContext, paramAttributeSet, 0); } public SignatureViewDemo(Context paramContext, AttributeSet paramAttributeSet, int paramInt) { super(paramContext, paramAttributeSet, paramInt); setFocusable(true); this.m_PenPaint = new Paint(); this.m_PenPaint.setAntiAlias(true); this.m_PenPaint.setColor(Color.BLACK); this.m_PenPaint.setStrokeWidth(5.0F); this.m_PenPaint.setStrokeJoin(Paint.Join.ROUND); this.m_PenPaint.setStrokeCap(Paint.Cap.ROUND); this.m_CurrentY = (0.0F / 0.0F); this.m_CurrentX = (0.0F / 0.0F); this.m_StrokeWidth = 5.0F; this.m_DesiredDash = 10.0F; this.m_BorderPaint = new Paint(); this.m_BorderPaint.setColor(Color.BLACK); this.m_BorderPaint.setStyle(Paint.Style.STROKE); this.m_BorderPaint.setStrokeWidth(this.m_StrokeWidth); } public void addBezier(Bezier paramBezier, float paramFloat1, float paramFloat2) { if (this.m_Bitmap == null) { this.m_Bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888); this.m_Canvas = new Canvas(this.m_Bitmap); } paramBezier.draw(this.m_Canvas, this.m_PenPaint, paramFloat1, paramFloat2); } public void addPoint(Point paramPoint) { if ((paramPoint.getX() < this.m_CropTopLeft.getX()) && (paramPoint.getX() >= 0.0F)) this.m_CropTopLeft.setX(paramPoint.getX()); if ((paramPoint.getY() < this.m_CropTopLeft.getY()) && (paramPoint.getY() >= 0.0F)) this.m_CropTopLeft.setY(paramPoint.getY()); if ((paramPoint.getX() > this.m_CropBotRight.getX()) && (paramPoint.getX() <= this.m_Canvas.getWidth())) this.m_CropBotRight.setX(paramPoint.getX()); if ((paramPoint.getY() > this.m_CropBotRight.getY()) && (paramPoint.getY() <= this.m_Canvas.getHeight())) this.m_CropBotRight.setY(paramPoint.getY()); this.m_Points.add(paramPoint); drawPoints(); } // public void clear() { // if (this.m_Canvas == null) // this.m_Canvas.drawColor(0, PorterDuff.Mode.CLEAR); // invalidate(); // // return; // } public void clear() { if (this.m_Canvas == null) return; while (m_Empty) { m_Canvas.drawColor(0, PorterDuff.Mode.CLEAR); m_Empty = true; invalidate(); return; } } public void drawBitmap(Bitmap paramBitmap) { clear(); if ((paramBitmap != null) && (this.m_Canvas != null) && (this.m_Canvas.getWidth() != 0) && (this.m_Canvas.getHeight() != 0)) { Matrix localMatrix = new Matrix(); localMatrix.setRectToRect( new RectF(0.0F, 0.0F, paramBitmap.getWidth(), paramBitmap .getHeight()), new RectF(0.0F, 0.0F, this.m_Canvas.getWidth(), this.m_Canvas.getHeight()), Matrix.ScaleToFit.CENTER); this.m_Canvas.drawBitmap(paramBitmap, localMatrix, null); m_Empty = false; } invalidate(); } public void drawPoints() { if ((m_Points.size() >= 4) && (4 + this.m_PointIndex <= this.m_Points.size())) { Point localPoint1 = (Point) this.m_Points.get(this.m_PointIndex); Point localPoint2 = (Point) this.m_Points .get(1 + this.m_PointIndex); Point localPoint3 = (Point) this.m_Points .get(2 + this.m_PointIndex); Point localPoint4 = (Point) this.m_Points .get(3 + this.m_PointIndex); Bezier localBezier = new Bezier(localPoint1, localPoint2, localPoint3, localPoint4); localBezier.setColor(Color.GREEN); float f = strokeWidth(8.0F / localPoint4.velocityFrom(localPoint1)); addBezier(localBezier, this.m_LastWidth, f); invalidate(); this.m_LastWidth = f; this.m_PointIndex = (3 + this.m_PointIndex); m_Empty = false; } } public boolean isEmpty() { return m_Empty; } public Bitmap getBitmap() { return this.m_Bitmap; } public int getColor() { return this.color; } protected void onDraw(Canvas paramCanvas) { if (this.m_Bitmap != null) paramCanvas.drawBitmap(this.m_Bitmap, 0.0F, 0.0F, null); } protected void onMeasure(int paramInt1, int paramInt2) { int i = View.MeasureSpec.getSize(paramInt1); int j = View.MeasureSpec.getSize(paramInt2); this.m_CropTopLeft = new Point(i, j); this.m_CropBotRight = new Point(0.0F, 0.0F); setMeasuredDimension(i, j); } protected void onSizeChanged(int paramInt1, int paramInt2, int paramInt3, int paramInt4) { Bitmap localBitmap = Bitmap.createBitmap(paramInt1, paramInt2, Bitmap.Config.ARGB_8888); this.m_Canvas = new Canvas(localBitmap); float f1 = 2.0F * (this.m_Canvas.getWidth() + this.m_Canvas.getHeight() - 2.0F * this.m_StrokeWidth); float f2 = f1 * this.m_DesiredDash / (Math.round(f1 / (4.0F * this.m_DesiredDash)) * (4.0F * this.m_DesiredDash)); Paint localPaint = this.m_BorderPaint; float[] arrayOfFloat = new float[2]; arrayOfFloat[0] = f2; arrayOfFloat[1] = f2; localPaint.setPathEffect(new DashPathEffect(arrayOfFloat, f2 / 2.0F)); clear(); if (this.m_Bitmap != null) { Rect localRect = new Rect(0, 0, this.m_Canvas.getWidth(), this.m_Canvas.getHeight()); this.m_Canvas.drawBitmap(this.m_Bitmap, null, localRect, null); m_Empty = false; } this.m_Bitmap = localBitmap; } public boolean onTouchEvent(MotionEvent paramMotionEvent) { int i = 0xFF & paramMotionEvent.getAction(); if (i == 0) { this.m_CurrentX = paramMotionEvent.getX(); this.m_CurrentY = paramMotionEvent.getY(); addPoint(new Point(this.m_CurrentX, this.m_CurrentY, paramMotionEvent.getEventTime())); getParent().requestDisallowInterceptTouchEvent(true); } // while (m_Empty) { if ((i == 1) || (i == 3)) { this.m_CurrentY = (0.0F / 0.0F); this.m_CurrentX = (0.0F / 0.0F); this.m_Points.clear(); this.m_PointIndex = 0; getParent().requestDisallowInterceptTouchEvent(false); } // if ((this.m_Points.size() < 4) || (4 + this.m_PointIndex > // this.m_Points.size())) // while (1 + this.m_PointIndex <= this.m_Points.size()) drawPoints(); if ((i == 2) || (i == 1)) { for (int j = 0; j < paramMotionEvent.getHistorySize(); j++) addPoint(new Point(paramMotionEvent.getHistoricalX(j), paramMotionEvent.getHistoricalY(j), paramMotionEvent.getHistoricalEventTime(j))); addPoint(new Point(paramMotionEvent.getX(), paramMotionEvent.getY(), paramMotionEvent.getEventTime())); } // } return true; } public void setColor(int paramInt) { this.color = Color.BLACK; } public Point getCropBotRight() { return this.m_CropBotRight; } public Point getCropTopLeft() { return this.m_CropTopLeft; } // public float strokeWidth(float paramFloat) { // if (paramFloat > 11.0F) // paramFloat = 10.0F; // if (paramFloat < 5.0F) // paramFloat = 6.0F; // return paramFloat; // } public float strokeWidth(float paramFloat) { if (paramFloat > 11.0F) paramFloat = 10.0F; while (m_Empty) { if (paramFloat < 5.0F) paramFloat = 6.0F; return paramFloat; } return paramFloat; } } 

Point.java

  private long time; private float x; private float y; public Point(float paramFloat1, float paramFloat2) { this.x = paramFloat1; this.y = paramFloat2; } public Point(float paramFloat1, float paramFloat2, long paramLong) { this.x = paramFloat1; this.y = paramFloat2; this.time = paramLong; } protected float distanceTo(Point paramPoint) { float f1 = this.x - paramPoint.getX(); float f2 = this.y - paramPoint.getY(); return FloatMath.sqrt(f1 * f1 + f2 * f2); } public long getTime() { return this.time; } public float getX() { return this.x; } public float getY() { return this.y; } public void setX(float paramFloat) { this.x = paramFloat; } public void setY(float paramFloat) { this.y = paramFloat; } public float velocityFrom(Point paramPoint) { return distanceTo(paramPoint) / (this.time - paramPoint.time); } } 

Bezier.java

 public class Bezier { private Point controlPointOne; private Point controlPointTwo; private int drawSteps; private Point endPoint; private int mColor; private Point startPoint; public Bezier() { } public Bezier(Point paramPoint1, Point paramPoint2, Point paramPoint3, Point paramPoint4) { this.startPoint = paramPoint1; this.controlPointOne = paramPoint2; this.controlPointTwo = paramPoint3; this.endPoint = paramPoint4; this.drawSteps = ((int) (paramPoint1.distanceTo(paramPoint2) + paramPoint2.distanceTo(paramPoint3) + paramPoint3 .distanceTo(paramPoint4))); } public void draw(Canvas paramCanvas, Paint paramPaint, float paramFloat1, float paramFloat2) { float f1 = paramFloat2 - paramFloat1; for (int i = 0; i < this.drawSteps; i++) { float f2 = i / this.drawSteps; float f3 = f2 * f2; float f4 = f3 * f2; float f5 = 1.0F - f2; float f6 = f5 * f5; float f7 = f6 * f5; float f8 = f7 * this.startPoint.getX() + f2 * (3.0F * f6) * this.controlPointOne.getX() + f3 * (3.0F * f5) * this.controlPointTwo.getX() + f4 * this.endPoint.getX(); float f9 = f7 * this.startPoint.getY() + f2 * (3.0F * f6) * this.controlPointOne.getY() + f3 * (3.0F * f5) * this.controlPointTwo.getY() + f4 * this.endPoint.getY(); paramPaint.setColor(getColor()); paramPaint.setStrokeWidth(paramFloat1 + f4 * f1); paramCanvas.drawPoint(f8, f9, paramPaint); } } public int getColor() { return this.mColor; } public Point getControlPointOne() { return this.controlPointOne; } public Point getControlPointTwo() { return this.controlPointTwo; } public int getDrawSteps() { return this.drawSteps; } public Point getEndPoint() { return this.endPoint; } public Point getStartPoint() { return this.startPoint; } public void setColor(int paramInt) { this.mColor = Color.BLACK; } public void setControlPointOne(Point paramPoint) { this.controlPointOne = paramPoint; } public void setControlPointTwo(Point paramPoint) { this.controlPointTwo = paramPoint; } public void setDrawSteps(int paramInt) { this.drawSteps = paramInt; } public void setEndPoint(Point paramPoint) { this.endPoint = paramPoint; } public void setStartPoint(Point paramPoint) { this.startPoint = paramPoint; } 

}

  • Captura de pantalla
  • SetShadowLayer Diferencias de la API de Android
  • Cómo convertir rgb color a int en java
  • Dibujar mapa de bits girado con anti alias
  • Línea dinámicamente generada con brillo efectivo
  • Bitmapshader y canvas.scaling android
  • Android: Medir la altura del texto en una lona
  • ¿Cómo evitar que drawBitmap de Android sólo dibuje imágenes en negro?
  • 4 Solutions collect form web for “Android: firma digital con Bezier”

    Cambie el método de dibujo en la clase Bezier para:

     public void draw(Canvas canvas, Paint paint, float startWidth, float endWidth) { float originalWidth = paint.getStrokeWidth(); float widthDelta = endWidth - startWidth; for (int i = 0; i < drawSteps; i++) { float t = ((float) i) / drawSteps; float tt = t * t; float ttt = tt * t; float u = 1 - t; float uu = u * u; float uuu = uu * u; float x = uuu * startPoint.x; x += 3 * uu * t * getControlPointOne().x; x += 3 * u * tt * getControlPointTwo().x; x += ttt * endPoint.x; float y = uuu * startPoint.y; y += 3 * uu * t * getControlPointOne().y; y += 3 * u * tt * getControlPointTwo().y; y += ttt * endPoint.y; paint.setStrokeWidth(startWidth + ttt * widthDelta); canvas.drawPoint(x, y, paint); } paint.setStrokeWidth(originalWidth); } 

    Tienes que ver cuántos puntos se dibujan en la clase Bezier y sumarlos.

    De su código: Usted está recolectando 4 puntos y dibuja una curva de Bezier sobre ellos. Esto significa que el algoritmo – por diseño – se perderá la mitad de los puntos de la muestra.

    Otras opciones: 1. Cree su propia curva de Bezier o orden inferior (diga – orden 3) – y luego perderá sólo 1/3 de los puntos. Esto hace que el problema sea inútil, ya que desea conservar menos datos que los muestreados. 2. Cree una curva Bezier de orden superior que pueda aproximar la firma completa.

    Sin embargo, puede intentar averiguar qué puntos desea seleccionar para obtener una curva de Bezier que esté más cerca de la firma: seleccione la parte superior de la letra 'l' como punto final de una curva de Bézier y el inicio De otro dará mejores resultados.

    Puede utilizar

    código

     public class MySignatureView extends View { private Path mPath; private Paint mPaint; private Bitmap mBitmap; private Canvas mCanvas; private int bgColor; private float curX, curY; private boolean isDragged = false; private static final int TOUCH_TOLERANCE = 4; private static final int STROKE_WIDTH = 2; public MySignatureView(Context context) { super(context); init(); } public MySignatureView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public MySignatureView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } private void init() { setFocusable(true); bgColor = Color.WHITE; mPath = new Path(); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setColor(bgColor ^ 0x00FFFFFF); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(STROKE_WIDTH); } public void setSigColor(int color) { mPaint.setColor(color); } public void setSigColor(int a, int r, int g, int b) { mPaint.setARGB(a, r, g, b); } public void clearSig() { if (mCanvas != null) { mCanvas.drawColor(bgColor); mCanvas.drawPaint(mPaint); mPath.reset(); invalidate(); } } public Bitmap getImage() { return this.mBitmap; } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { int bitW = mBitmap != null ? mBitmap.getWidth() : 0; int bitH = mBitmap != null ? mBitmap.getWidth() : 0; if (bitW >= w && bitH >= h) { return; } if (bitW < w) bitW = w; if (bitH < h) bitH = h; Bitmap newBitmap = Bitmap.createBitmap(bitW, bitH, Bitmap.Config.ARGB_8888); Canvas newCanvas = new Canvas(); newCanvas.setBitmap(newBitmap); if (mBitmap != null) { newCanvas.drawBitmap(mBitmap, 0, 0, null); } mBitmap = newBitmap; mCanvas = newCanvas; } @Override protected void onDraw(Canvas canvas) { canvas.drawBitmap(mBitmap, 0, 0, mPaint); canvas.drawPath(mPath, mPaint); } @Override public boolean onTouchEvent(MotionEvent event) { float x = event.getX(); float y = event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: touchDown(x, y); break; case MotionEvent.ACTION_MOVE: touchMove(x, y); break; case MotionEvent.ACTION_UP: touchUp(); break; } invalidate(); return true; } private void touchDown(float x, float y) { mPath.reset(); mPath.moveTo(x, y); curX = x; curY = y; isDragged = false; } private void touchMove(float x, float y) { float dx = Math.abs(x - curX); float dy = Math.abs(y - curY); if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) { mPath.quadTo(curX, curY, (x + curX) / 2, (y + curY) / 2); curX = x; curY = y; isDragged = true; } } private void touchUp() { if (isDragged) { mPath.lineTo(curX, curY); } else { mPath.lineTo(curX+2, curY+2); } mCanvas.drawPath(mPath, mPaint); mPath.reset(); } } 

    Usted puede utilizar esto, también he adjuntado el xml en la parte inferior:

     import java.io.File; import java.io.FileOutputStream; import java.util.Calendar; import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.content.ContextWrapper; import android.content.DialogInterface; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.RectF; import android.os.Bundle; import android.os.Environment; import android.provider.MediaStore.Images; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup.LayoutParams; import android.view.Window; import android.widget.Button; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.Toast; public class SignatureCapture extends Activity { public LinearLayout mContent; public signature mSignature; public Button mClear, mGetSign, mCancel; public static String tempDir; public int count = 1; public String current = null; public static Bitmap mBitmap; public View mView; public File mypath; private String uniqueId; private EditText yourName; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.signature); // tempDir = Environment.getExternalStorageDirectory() + "/" + // getResources().getString(R.string.external_dir) + "/"; ContextWrapper cw = new ContextWrapper(getApplicationContext()); // File directory = // cw.getDir(getResources().getString(R.string.external_dir), // Context.MODE_PRIVATE); File directory = new File(Environment.getExternalStorageDirectory() + "/GLP_Images"); if (!directory.exists()) directory.mkdir(); // directory is created; // prepareDirectory(); uniqueId = getTodaysDate() + "_" + getCurrentTime(); current = uniqueId + ".png"; mypath = new File(directory, current); mContent = (LinearLayout) findViewById(R.id.linearLayout); mSignature = new signature(this, null); mSignature.setBackgroundColor(Color.WHITE); mContent.addView(mSignature, LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); mClear = (Button) findViewById(R.id.clear); mGetSign = (Button) findViewById(R.id.getsign); mGetSign.setEnabled(false); mCancel = (Button) findViewById(R.id.cancel); mView = mContent; // yourName = (EditText) findViewById(R.id.yourName); mClear.setOnClickListener(new OnClickListener() { public void onClick(View v) { Log.v("log_tag", "Panel Cleared"); mSignature.clear(); mGetSign.setEnabled(false); } }); mGetSign.setOnClickListener(new OnClickListener() { public void onClick(View v) { Log.v("log_tag", "Panel Saved"); // boolean error = captureSignature(); // if(error){ mView.setDrawingCacheEnabled(true); mSignature.save(mView); // Bundle b = new Bundle(); // b.putString("status", "done"); /* * Intent intent = new * Intent(SignatureCapture.this,SigntuareCaptureActivity.class); * // intent.putExtra("imagePath",mypath); * startActivity(intent); //intent.putExtra("status", "done"); * //setResult(RESULT_OK,intent); finish(); // } */ AlertDialog.Builder dialog = new AlertDialog.Builder( SignatureCapture.this); dialog.setMessage("Details saved"); dialog.setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); dialog.show(); } }); mCancel.setOnClickListener(new OnClickListener() { public void onClick(View v) { Log.v("log_tag", "Panel Canceled"); Bundle b = new Bundle(); b.putString("status", "cancel"); Intent intent = new Intent(); intent.putExtras(b); setResult(RESULT_OK, intent); finish(); } }); } @Override protected void onDestroy() { Log.w("GetSignature", "onDestory"); super.onDestroy(); } // private boolean captureSignature() // { // // boolean error = false; // String errorMessage = ""; // // // if(yourName.getText().toString().equalsIgnoreCase("")) // { // errorMessage = errorMessage + "Please enter your Name\n"; // error = true; // } // // if(error) // { // Toast toast = Toast.makeText(this, errorMessage, Toast.LENGTH_SHORT); // toast.setGravity(Gravity.TOP, 105, 50); // toast.show(); // } // // return error; // } private String getTodaysDate() { final Calendar c = Calendar.getInstance(); int todaysDate = (c.get(Calendar.YEAR) * 10000) + ((c.get(Calendar.MONTH) + 1) * 100) + (c.get(Calendar.DAY_OF_MONTH)); Log.w("DATE:", String.valueOf(todaysDate)); return (String.valueOf(todaysDate)); } private String getCurrentTime() { final Calendar c = Calendar.getInstance(); int currentTime = (c.get(Calendar.HOUR_OF_DAY) * 10000) + (c.get(Calendar.MINUTE) * 100) + (c.get(Calendar.SECOND)); Log.w("TIME:", String.valueOf(currentTime)); return (String.valueOf(currentTime)); } private boolean prepareDirectory() { try { if (makedirs()) { return true; } else { return false; } } catch (Exception e) { e.printStackTrace(); Toast.makeText( this, "Could not initiate File System.. Is Sdcard mounted properly?", 1000).show(); return false; } } private boolean makedirs() { File tempdir = new File(tempDir); if (!tempdir.exists()) tempdir.mkdirs(); if (tempdir.isDirectory()) { File[] files = tempdir.listFiles(); for (File file : files) { if (!file.delete()) { System.out.println("Failed to delete " + file); } } } return (tempdir.isDirectory()); } public class signature extends View { private static final float STROKE_WIDTH = 5f; private static final float HALF_STROKE_WIDTH = STROKE_WIDTH / 2; private Paint paint = new Paint(); private Path path = new Path(); private float lastTouchX; private float lastTouchY; private final RectF dirtyRect = new RectF(); public signature(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); } public void save(View v) { Log.v("log_tag", "Width: " + v.getWidth()); Log.v("log_tag", "Height: " + v.getHeight()); if (mBitmap == null) { mBitmap = Bitmap.createBitmap(mContent.getWidth(), mContent.getHeight(), Bitmap.Config.RGB_565); } Canvas canvas = new Canvas(mBitmap); try { FileOutputStream mFileOutStream = new FileOutputStream(mypath); v.draw(canvas); mBitmap.compress(Bitmap.CompressFormat.PNG, 90, mFileOutStream); mFileOutStream.flush(); mFileOutStream.close(); String url = Images.Media.insertImage(getContentResolver(), mBitmap, "title", null); // Log.v("log_tag","url: " + url); // //In case you want to delete the file // boolean deleted = mypath.delete(); // Log.v("log_tag","deleted: " + mypath.toString() + deleted); // //If you want to convert the image to string use base64 // converter } catch (Exception e) { Log.v("log_tag", e.toString()); } } public void clear() { path.reset(); 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(); mGetSign.setEnabled(true); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: path.moveTo(eventX, eventY); lastTouchX = eventX; lastTouchY = eventY; return true; case MotionEvent.ACTION_MOVE: case MotionEvent.ACTION_UP: resetDirtyRect(eventX, eventY); 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); } path.lineTo(eventX, eventY); break; default: debug("Ignored touch event: " + event.toString()); return false; } 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; } private void debug(String string) { } 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; } } private void resetDirtyRect(float eventX, float eventY) { dirtyRect.left = Math.min(lastTouchX, eventX); dirtyRect.right = Math.max(lastTouchX, eventX); dirtyRect.top = Math.min(lastTouchY, eventY); dirtyRect.bottom = Math.max(lastTouchY, eventY); } } } 

     <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/linearLayout1" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/header_bg" android:gravity="center" android:text="Signature" android:textColor="@android:color/white" android:textSize="20dp" android:textStyle="bold" /> <LinearLayout android:id="@+id/linearLayout" android:layout_width="match_parent" android:layout_weight="1" android:layout_height="wrap_content" android:orientation="vertical" /> <LinearLayout android:id="@+id/linearLayout2" android:layout_width="match_parent" android:layout_height="wrap_content" > <Button android:id="@+id/cancel" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight=".30" android:text="Cancel" android:visibility="gone" /> <Button android:id="@+id/clear" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="Clear" /> <Button android:id="@+id/getsign" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="Save" /> </LinearLayout> </LinearLayout> 
    FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.