Cómo dibujar una ruta con ancho de trazo variable

Mi código es básicamente de este ejemplo ( http://corner.squareup.com/2010/07/smooth-signatures.html ) y las API de Google (FingerPaint), pero ahora quiero usar la clase VelocityTracker para cambiar el ancho de trazo Dependiendo de la velocidad de mi dedo.

Pensé que podría dividir un camino en partes más pequeñas, pero no encontré ningún ejemplo. También hay este segundo post ( http://corner.squareup.com/2012/07/smoother-signatures.html ) pero no tengo una clase de curva bezier específica ni recojo todos los puntos en un ArrayList para que su ejemplo para Ajustar el ancho de carrera no es muy útil.

¿Alguien tiene una idea de cómo manejar esto? Comencé a aprender código hace dos semanas así que soy bastante nuevo en todo esto.

Edit: He intentado implementar la velocidad de mis MotionEvents y he usado LogCat para rastrear la velocidad actual mientras ejecuta la aplicación. Funcionó pero cuando intenté usar la velocidad como parte del parámetro para mPaint.setStrokeWidth no conseguí lo que realmente quería. El ancho del camino que dibujo en mi lienzo estaba cambiando todo el tiempo desde el momento en que empecé a dibujar una línea hasta que moví mi dedo hacia arriba. Así que por eso quiero dividir un camino en partes más pequeñas, porque como es ahora, sólo la velocidad de seguimiento pasado afecta a la longitud del trazo.

 public class SignatureView extends View { private static final String TAG = SignatureView.class.getSimpleName(); private static final float STROKE_WIDTH = 10; private static final float HALF_STROKE_WIDTH = STROKE_WIDTH / 2; private final double TOUCH_TOLERANCE = 5; private int h = getResources().getDisplayMetrics().heightPixels; private int w = getResources().getDisplayMetrics().widthPixels; private Path mPath = new Path(); private Paint mPaint = new Paint(); private Paint mBitmapPaint = new Paint(Paint.DITHER_FLAG); private Bitmap mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); private Canvas mCanvas = new Canvas(mBitmap); private float mX, mY; private float lastTouchX, lastTouchY; private final RectF dirtyRect = new RectF(); public SignatureView(Context context, AttributeSet attrs) { super(context, attrs); mPaint.setAntiAlias(true); mPaint.setColor(Color.BLACK); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeJoin(Paint.Join.ROUND); mPaint.setStrokeWidth(INITIAL_STROKE_WIDTH); Log.d(TAG, "TOUCH_TOLERANCE = " +TOUCH_TOLERANCE); } @Override protected void onDraw(Canvas canvas) { canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint); canvas.drawPath(mPath, mPaint); } @Override public boolean onTouchEvent(MotionEvent event) { float eventX = event.getX(); float eventY = event.getY(); int historySize = event.getHistorySize(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: resetDirtyRect(eventX, eventY); mPath.reset(); mPath.moveTo(eventX, eventY); mX = eventX; mY = eventY; break; case MotionEvent.ACTION_MOVE: float dx = Math.abs(eventX - mX); float dy = Math.abs(eventY - mY); if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) { mPath.quadTo(mX, mY, (eventX + mX)/2, (eventY + mY)/2); mX = eventX; mY = eventY; } for (int i = 0; i < historySize; i++) { float historicalX = event.getHistoricalX(i); float historicalY = event.getHistoricalY(i); expandDirtyRect(historicalX, historicalY); } break; case MotionEvent.ACTION_UP: for (int i = 0; i < historySize; i++) { float historicalX = event.getHistoricalX(i); float historicalY = event.getHistoricalY(i); expandDirtyRect(historicalX, historicalY); } mPath.lineTo(mX, mY); mCanvas.drawPath(mPath, mPaint); mPath.reset(); break; default: Log.d(TAG, "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; } 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); } } 

Puede usar dividir el objeto de ruta cada vez que cambie el valor de su trazo dependiendo de la velocidad. En su clase SignatureView add

 private Path mPath = new Path(); ArrayList<Path> mPaths = new ArrayList<Path>(); 

Y tomar otro ArrayList para mantener el valor de trazo para cada ruta

 ArrayList<int> strokes = new ArrayList<int>(); 

Agregue una variable lastStroke junto con lastTouchX y lastTouchY . Te recomiendo que hagas lastStroke de tipo int .

 private int lastStroke = -1; //give an initial value 

Ahora su método onTouchEvent debe ser algo como esto

 @Override public boolean onTouchEvent(MotionEvent event) { float eventX = event.getX(); float eventY = event.getY(); int historySize = event.getHistorySize(); int eventStroke= //calculate stroke size with velocity and make it between 1-10 or any range you seem fit switch (event.getAction()) { case MotionEvent.ACTION_DOWN: resetDirtyRect(eventX, eventY); mPath.reset(); mPath.moveTo(eventX, eventY); mX = eventX; mY = eventY; break; case MotionEvent.ACTION_MOVE: float dx = Math.abs(eventX - mX); float dy = Math.abs(eventY - mY); if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) { if(lastStroke != evetnStroke){ mPath = new Path(); mPath.moveTo(mX,mY); mPaths.Add(mPath); mStrokes.Add(eventStroke); } mPath.quadTo(mX, mY, (eventX + mX)/2, (eventY + mY)/2); mX = eventX; mY = eventY; } for (int i = 0; i < historySize; i++) { float historicalX = event.getHistoricalX(i); float historicalY = event.getHistoricalY(i); expandDirtyRect(historicalX, historicalY); } break; case MotionEvent.ACTION_UP: for (int i = 0; i < historySize; i++) { float historicalX = event.getHistoricalX(i); float historicalY = event.getHistoricalY(i); expandDirtyRect(historicalX, historicalY); } mPath.lineTo(mX, mY); break; default: Log.d(TAG, "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; lastStroke = eventStroke; return true; } 

Y su método de retiro sería

 @Override protected void onDraw(Canvas canvas) { for(int i=0; i<mPaths.size();i++){ mPaint.setStrokeWidth(strokes.get(i)); canvas.drawPath(mPaths.get(i), mPaint); } } 

Esta es la idea básica. Es necesario modificarlo para que funcione.

  • Comportamiento extraño al dibujar un anillo usando Path.arcTo () en Android
  • Android dibuja texto en rectángulo en el centro y recórtalo si es necesario
  • Los colores de ShapeRenderer dejan de funcionar al renderizar imágenes con SpriteBatch
  • Consejos sobre dibujo de alto rendimiento en Android
  • Android: ¿Cómo obtener una vista personalizada para volver a dibujar parcialmente?
  • ¿Una manera fácil de dibujar una línea punteada recta en libgdx?
  • ¿Cómo crear un juego de pista de carreras?
  • Cómo asignar coordenadas de marco a superposición en la visión
  • Crear lista de capas con esquinas redondeadas mediante programación
  • Cómo dibujar un círculo con animación en android con el tamaño del círculo basado en un valor
  • Dibuje Bitmap en ImageView personalizado y obtenga las coordenadas de ImageView independientemente del dispositivo
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.