2016-08-01 14 views
2

Ich arbeite an einem Projekt, wo ich Spiegel der Zeichnung erstellen. meine Hauptlogik funktioniert gut. Nur die Sache, die Problem verursacht, ist Wiederholen und Funktionalität rückgängig machen. Ich habe viel gesucht. Methoden implementieren, aber keinen Erfolg erzielen. Folgendes ist meine Zeichenklasse.Undo und Redo Funktionalität in android Zeichnung App mit Canvas

DrawingView.java

private ArrayList<Path> paths = new ArrayList<Path>(); 
private ArrayList<Path> undonePaths = new ArrayList<Path>(); 

public DrawingView(Context context, AttributeSet attrs){ 
    super(context, attrs); 
    this.context=context; 
    setupDrawing(); 


} 

//setup drawing 
private void setupDrawing(){ 

    //prepare for drawing and setup paint stroke properties 
    brushSize = getResources().getInteger(R.integer.small_size); 
    lastBrushSize = brushSize; 
    drawPath = new Path(); 
    drawPath1 = new Path(); 
    drawPaint = new Paint(); 
    drawPaint.setColor(paintColor); 
    drawPaint.setAntiAlias(true); 
    drawPaint.setStrokeWidth(brushSize); 
    drawPaint.setStyle(Paint.Style.STROKE); 
    drawPaint.setStrokeJoin(Paint.Join.ROUND); 
    drawPaint.setStrokeCap(Paint.Cap.ROUND); 
    canvasPaint = new Paint(Paint.DITHER_FLAG); 
} 

//size assigned to view 
@Override 
protected void onSizeChanged(int w, int h, int oldw, int oldh) { 


    super.onSizeChanged(w, h, oldw, oldh); 
    canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); 
    width=w; 
    height=h; 
    Log.d("width,height", w + " , " + h); 
    drawCanvas = new Canvas(canvasBitmap); 




} 

//draw the view - will be called after touch event 
@Override 
protected void onDraw(Canvas canvas) { 

    for (Path p : paths){canvas.drawPath(p, drawPaint);} 
    canvas.drawPath(drawPath, drawPaint); 
    Log.i("OnDRAWING", "REACH ON DRAW"); 
    /*canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint); 
    canvas.drawPath(drawPath, drawPaint); 
    canvas.drawPath(drawPath1, drawPaint);*/ 






} 

//register user touches as drawing action 
@Override 
public boolean onTouchEvent(MotionEvent event) { 



    float touchX = event.getX(); 
    float touchY = event.getY(); 
    //respond to down, move and up events 
    switch (event.getAction()) { 
    case MotionEvent.ACTION_DOWN: 
     drawPath.reset(); 
     undonePaths.clear(); 
     drawPath.moveTo(touchX, touchY); 
     undonePaths.clear(); 



     break; 
    case MotionEvent.ACTION_MOVE: 
     drawPath.lineTo(touchX, touchY); 


     break; 
    case MotionEvent.ACTION_UP: 
     drawPath.lineTo(touchX, touchY); 
     drawCanvas.drawPath(drawPath, drawPaint);// commit the path to our offscreen 
     paths.add(drawPath); 
     drawCanvas.drawPath(drawPath, drawPaint); 
     drawPath.reset(); 

     drawCanvas.drawPath(drawPath1, drawPaint); 
     drawPath1.reset(); 

     break; 
    default: 
     return false; 
    } 
    //redraw 
    invalidate(); 
    return true; 

} 

was ich hier fehlt? Irgendwelche Vorschläge/Ideen/Beispiele, was ist der beste Weg, um diese Art von Funktionalität in meinem Projekt zu implementieren?

Antwort

1

Leinwand Zeichnung ist eine Art hierarchisch in der Zeichnung geschieht in der Reihenfolge, dass Sie sie tun.

Also alle Zeichnung sollte in onDraw und nur hier erfolgen.

Ihre Zeichenereignisse sollten auf einen Stapel gezogen werden. Sie speichern keine Leinwand. Sie speichern nur die Vorgänge, die ausgeführt werden sollen, wenn die Zeichnung schließlich auftritt (beispielsweise Koordinaten, Breite und Farbe eines Pfades).

Eine "Rückgängig" -Operation kann ausgeführt werden, indem Sie aus dem Zeichnungsstapel herausspringen und das Ereignis auf einen "Redo" - Stapel schieben. Das "Redo" -Ereignis kann durch Aufrufen des "Redo" -Stapels und Zurückschieben des "Drawing" -Stapels erfolgen.

In onDraw10 Methode Ihrer Ansicht, nur durch die Zeichnung Ereignisse scannen und auf der Leinwand zeichnen.

EDIT:

Die onDraw() Methode würde Ihre Zeichenoperationen nur durchlaufen. Also zuerst könnten Sie eine interface genannt haben DrawEvent etwa so:

public interface DrawEvent { 
    void draw(Canvas c); 
} 

Dann in Ihrer View-Klasse haben Sie Ihre Sammlung von DrawEvents und durchlaufen sie in onDraw(Canvas c).

public class MyView extends View { 
    Deque<DrawEvent> drawEvents = new LinkedList<DrawEvent>(); 

    @Override 
    public void onDraw(Canvas c) { 
     for (DrawEvent e : drawEvents) { 
      e.draw(c); 
     } 
    } 
} 
+0

danke für die schnelle Antwort. Ich verstehe den Fluss. Kannst du mir sagen, was ich schreiben soll? es ist etwas verwirrend für mich. Ich werde jede Hilfe schätzen. –

+0

Ich habe es bearbeitet, um zu zeigen, wie die onDraw-Methode funktionieren würde. Der Punkt, den ich versuche zu vermitteln, ist, dass Sie den Canvas nicht außerhalb der 'OnDraw'- oder' Draw'-Methoden einer View speichern oder verwenden können. Sie müssen die Ereignisse und Anweisungen zum Zeichnen speichern und in der richtigen Reihenfolge speichern. – DeeV

+0

Ich habe zuvor den Pfad zur Liste hinzugefügt. Jetzt, da ich eine Schnittstelle implementiere, bin ich verwirrt, wo man hinzufügt und was zu drawEvents addiert. –