Usando el código que encontré en esta respuesta de StackOverflow , puedo dibujar con éxito cualquier cosa en un lienzo con el dedo, y veré lo que dibujo mientras lo dibujo. A partir de esto, quiero hacer que una función se active al presionar un botón que hará dos cosas:
Para hacerlo, he modificado ligeramente el código de onTouchEvent , por lo que almacena cada punto dibujado en consecuencia:
@Override public boolean onTouchEvent(MotionEvent event) { StrokePoint point; switch (event.getAction()){ case MotionEvent.ACTION_DOWN: mPath.moveTo(event.getX(), event.getY()); // Retrieve strokes in memory stroke_buffer = new Stroke(); stroke_buffer.points = new ArrayList<StrokePoint>(); point = new StrokePoint(); point.x = event.getX(); point.y = event.getY(); stroke_buffer.points.add( point ); break; case MotionEvent.ACTION_MOVE: mPath.lineTo(event.getX(), event.getY()); // Retrieve strokes in memory point = new StrokePoint(); point.x = event.getX(); point.y = event.getY(); stroke_buffer.points.add( point ); invalidate(); break; case MotionEvent.ACTION_UP: // Retrieve strokes in memory strokes.add(stroke_buffer); break; default: break; } return true; }De esa manera, puedo cargar los puntos X e Y más tarde en bucles (al menos esa es la idea). El problema es que no estoy seguro de cómo activar el "redibujar" en el lienzo para cada línea. Traté de almacenar el lienzo de "onDraw" de esta manera:
@Override protected void onDraw(Canvas canvas) { canvas.drawPath(mPath, mPaint); // For trying to make the "redraw" later this.mCanvas = canvas; super.onDraw(canvas); }Y luego, hago este método para el botón que quiero borrar y reproducir los trazos dibujados previamente:
public void replayStrokes() { // I start a new path from scratch ad-hoc the "redraw" animation. mPath = new Path(); Log.i("SANDBOX_INFO", "Button pressed"); // Intention here is leaving the "whiteboard" clear again. mCanvas.drawRGB(255, 255, 255); invalidate(); this.draw(mCanvas); SystemClock.sleep(1000); // Redraw "line by line" loop mPath.moveTo(strokes.get(0).points.get(0).x, strokes.get(0).points.get(0).y); for (int i = 0; i < strokes.size(); i++) { for (int j = 0; j < strokes.get(i).points.size(); j++) { if (i == 0 && j == 0) continue; mPath.lineTo(strokes.get(i).points.get(j).x, strokes.get(i).points.get(j).y); mCanvas.drawPath(mPath, mPaint); invalidate(); this.draw(mCanvas); SystemClock.sleep(100); } } } Cuando presiono el botón, el método replayStrokes no se comporta como se esperaba. Es como si se quedara "pensando" (procesando) y, cuando menos te lo esperas, refresca todos los cambios de un solo golpe; en cambio, quiero que sea una animación fluida en la que puedas ver todo el Camino previamente dibujado con el dedo, reproducido línea por línea, punto por punto. ¿Qué estoy haciendo mal? ¿Qué debo cambiar para obtener el comportamiento esperado?
Terminé encontrando una solución gracias al comentario de @VitorHugoSchwaab. Pequeño recordatorio: se supone que todo el código que publiqué en esta pregunta está dentro de una public class DrawCanvas extends View . Eso dijo:
Entonces, dejé el "método de activación" así:
private int s, p; private boolean replay_mode; public void replayStrokes() { s = 0; p = 0; replay_mode = true; invalidate(); } Y modifiqué el método onDraw así (lo transformé en un Megamoth , pero eso lo puedo arreglar más tarde: P):
@Override protected void onDraw(Canvas canvas) { if (replay_mode) { if (s == 0 && p == 0) { Log.i("SANDBOX_INFO", "Replay Mode START"); canvas.drawRGB(255, 255, 255); p++; replayPath.reset(); replayPath.moveTo(strokes.get(0).points.get(0).x, strokes.get(0).points.get(0).y); invalidate(); } else { Log.i("SANDBOX_INFO", "Replaying --> S:" + s + " P:" + p); if (p == 0) { replayPath.moveTo(strokes.get(s).points.get(p).x, strokes.get(s).points.get(p).y); } else { replayPath.lineTo(strokes.get(s).points.get(p).x, strokes.get(s).points.get(p).y); canvas.drawPath(replayPath, mPaint); } int points_size = strokes.get(s).points.size(); if (s == strokes.size() - 1 && p == points_size - 1) { Log.i("SANDBOX_INFO", "Replay Mode END"); replay_mode = false; } else if (p == points_size - 1) { s++; p = 0; } else { p++; } } invalidate(); } else { canvas.drawPath(mPath, mPaint); } super.onDraw(canvas); }Esto funciona. Sin embargo, hay un efecto de falla de "parpadeo" mientras se repiten los trazos. Creo que eso podría deberse a que en realidad está "redibujando" toda la "ruta de reproducción" en cada cuadro. Basado en esta suposición, intentaré solucionar el problema cuando tenga más tiempo para codificar.