Reputation: 908
Using the code I found in this StackOverflow answer I successfully can draw anything in a Canvas by finger, and I will see what I draw while I draw it. From this, I want to make a function triggered on button press that will do two things:
In order to do so, I have slightly modificated the onTouchEvent
code, so it stores each drawn point accordingly:
@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;
}
That way, I can load the X and Y points later in loops (that's the idea at least). The problem is I am not sure how to trigger the "redraw" on the canvas for each line. I tried to store the canvas from the "onDraw" like this:
@Override
protected void onDraw(Canvas canvas) {
canvas.drawPath(mPath, mPaint);
// For trying to make the "redraw" later
this.mCanvas = canvas;
super.onDraw(canvas);
}
And then, I make this method for the button which I want to erase and replay the previously drawn strokes:
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);
}
}
}
When I press the button, the method replayStrokes
doesn't behave as expected. It's like it remains "thinking" (processing) and, when you least expect it, refreshes all the changes in a single blow; instead, I want it to be a smooth animation where you can see the entire Path previously drawn by finger, replayed line by line, point by point. What am I doing wrong? What should I change to obtain the expected behaviour?
Upvotes: 6
Views: 164
Reputation: 908
I ended up figuring out a solution thanks to @VitorHugoSchwaab 's comment. Little reminder: all the code I have posted in this question is supposed to be inside a public class DrawCanvas extends View
class. That said:
So, i left the "trigger method" like this:
private int s, p;
private boolean replay_mode;
public void replayStrokes() {
s = 0;
p = 0;
replay_mode = true;
invalidate();
}
And I modified the onDraw
method like this (I transformed it into a Megamoth, but that I can fix later :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);
}
This works. However, there's a glitchy effect of "flashing" while the strokes are replayed. I think that might be because it's actually "redrawing" the entire "replay path" on every frame. Based on this guess, I will try to workaround the issue when I have somemore time to code.
Upvotes: 1