2017-05-23 3 views
1

Je développe l'application de dessin, dans lequel l'utilisateur peut dessiner des formes comme le rectangle, le cercle, etc. L'utilisateur peut également faire un dessin à main levée (stylo).Annuler et rétablir sur la toile

Je souhaite ajouter une fonction d'annulation, de rétablissement. J'ai recherché et lu la plupart de réponse de SO pour annuler et refaire, mais tous sont liés aux chemins. Cela signifie qu'ils gèrent deux listes, une pour la liste des chemins tracée ou la seconde pour annuler la liste des chemins. C'est une bonne façon de travailler, mais c'est SEULEMENT si c'est un dessin à main levée ou si je travaille avec des chemins.

Ici j'appelle différents types de méthodes de toile pour différentes formes.

Aidez-moi à fournir l'annulation de dessin sur toile.

Voici mon code

public class DrawingView extends android.support.v7.widget.AppCompatImageView { 
    public static final int RECTANGLE = 1; 
    public static final int SQUARE = 2; 
    public static final int CIRCLE = 3; 
    public 

static final int LINE = 4; 
    public static final int SMOOTH_LINE = 5; 
    public static final int TRIANGLE = 6; 
    public static final int IMPORT_IMAGE = 7; 
    public static final int ERASER = 8; 

private static final float TOUCH_TOLERANCE = 5; 

private int color; 
private int currentShape; 

protected Paint mPaint; 
protected Bitmap mBitmap; 
protected Canvas mCanvas; 

private float mx, my; 
private float mStartX, mStartY; 

private int width, height; 

private boolean isDrawing = true; 

public static int TOUCH_STROKE_WIDTH = 3; 

public static int ERASER_WIDTH = 3; 

private Path mPath = new Path(); 

int countTouch = 0; 
float basexTriangle = 0; 
float baseyTriangle = 0; 

public DrawingView(Context context, int shape, int color) { 
    super(context); 
    initPaint(); 
} 

protected void initPaint() { 

    color = DrawingActivity.selectedColor; 
    currentShape = DrawingActivity.currentShape; 

    mPaint = new Paint(Paint.DITHER_FLAG); 
    mPaint.setAntiAlias(true); 
    mPaint.setDither(true); 
    mPaint.setColor(color); 
    if (DrawingActivity.isFill && !DrawingActivity.isEraser && currentShape != SMOOTH_LINE) { 
     mPaint.setStyle(Paint.Style.FILL); 
    } else { 
     mPaint.setStyle(Paint.Style.STROKE); 
    } 
    mPaint.setStrokeJoin(Paint.Join.ROUND); 
    mPaint.setStrokeCap(Paint.Cap.ROUND); 
    if (DrawingActivity.isEraser) { 
     mPaint.setStrokeWidth(ERASER_WIDTH); 
    } else { 
     mPaint.setStrokeWidth(TOUCH_STROKE_WIDTH); 
    } 
} 

@Override 
public boolean onTouchEvent(MotionEvent event) { 

    //Retrieve the point 
    mx = event.getX(); 
    my = event.getY(); 

    switch (event.getAction()) { 
     case MotionEvent.ACTION_DOWN: 
      initPaint(); 
      break; 
    } 

    switch (currentShape) { 
     case RECTANGLE: 
      onTouchEventRectangle(event); 
      break; 
     case SQUARE: 
      onTouchEventSquare(event); 
      break; 
     case CIRCLE: 
      onTouchEventCircle(event); 
      break; 
     case LINE: 
      onTouchEventLine(event); 
      break; 
     case SMOOTH_LINE: 
      onTouchEventSmoothLine(event); 
      break; 
     case TRIANGLE: 
      onTouchEventTriangle(event); 
      break; 
    } 

    return true; 
} 

@Override 
protected void onDraw(Canvas canvas) { 
    super.onDraw(canvas); 
    canvas.drawBitmap(mBitmap, 0, 0, mPaint); 

    if (isDrawing) { 
     switch (currentShape) { 
      case RECTANGLE: 
       onDrawRectangle(canvas); 
       break; 
      case SQUARE: 
       onDrawSquare(canvas); 
       break; 
      case CIRCLE: 
       onDrawCircle(canvas); 
       break; 
      case LINE: 
       onDrawLine(canvas); 
       break; 
      case SMOOTH_LINE: 
       onDrawLine(canvas); 
       break; 
      case TRIANGLE: 
       onDrawTriangle(canvas); 
       break; 
     } 
    } 

    //draw your element 
} 

private void onTouchEventRectangle(MotionEvent event) { 
    switch (event.getAction()) { 
     case MotionEvent.ACTION_DOWN: 
      isDrawing = true; 
      mStartX = mx; 
      mStartY = my; 
      invalidate(); 
      break; 
     case MotionEvent.ACTION_MOVE: 
      invalidate(); 
      break; 
     case MotionEvent.ACTION_UP: 
      isDrawing = false; 
      drawRectangle(mCanvas, mPaint); 
      invalidate(); 
      break; 
    } 
} 

private void onDrawRectangle(Canvas canvas) { 
    drawRectangle(canvas, mPaint); 
} 

private void drawRectangle(Canvas canvas, Paint paint) { 
    float right = mStartX > mx ? mStartX : mx; 
    float left = mStartX > mx ? mx : mStartX; 
    float bottom = mStartY > my ? mStartY : my; 
    float top = mStartY > my ? my : mStartY; 
    canvas.drawRect(left, top, right, bottom, paint); 
} 

@Override 
protected void onSizeChanged(int w, int h, int oldw, int oldh) { 
    super.onSizeChanged(w, h, oldw, oldh); 
    width = w; 
    height = h; 
    mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_4444); 
    mCanvas = new Canvas(mBitmap); 
} 

private void onDrawSquare(Canvas canvas) { 
    onDrawRectangle(canvas); 
} 

private void onTouchEventSquare(MotionEvent event) { 

    switch (event.getAction()) { 
     case MotionEvent.ACTION_DOWN: 
      isDrawing = true; 
      mStartX = mx; 
      mStartY = my; 
      invalidate(); 
      break; 
     case MotionEvent.ACTION_MOVE: 
      adjustSquare(mx, my); 
      invalidate(); 
      break; 
     case MotionEvent.ACTION_UP: 
      isDrawing = false; 
      adjustSquare(mx, my); 
      drawRectangle(mCanvas, mPaint); 
      invalidate(); 
      break; 
    } 
} 

/** 
* Adjusts current coordinates to build a square 
* 
* @param x 
* @param y 
*/ 
protected void adjustSquare(float x, float y) { 
    float deltaX = Math.abs(mStartX - x); 
    float deltaY = Math.abs(mStartY - y); 

    float max = Math.max(deltaX, deltaY); 

    mx = mStartX - x < 0 ? mStartX + max : mStartX - max; 
    my = mStartY - y < 0 ? mStartY + max : mStartY - max; 
} 

private void onDrawCircle(Canvas canvas) { 
    canvas.drawCircle(mStartX, mStartY, calculateRadius(mStartX, mStartY, mx, my), mPaint); 
} 

private void onTouchEventCircle(MotionEvent event) { 
    switch (event.getAction()) { 
     case MotionEvent.ACTION_DOWN: 
      isDrawing = true; 
      mStartX = mx; 
      mStartY = my; 
      invalidate(); 
      break; 
     case MotionEvent.ACTION_MOVE: 
      invalidate(); 
      break; 
     case MotionEvent.ACTION_UP: 
      isDrawing = false; 
      mCanvas.drawCircle(mStartX, mStartY, 
        calculateRadius(mStartX, mStartY, mx, my), mPaint); 
      invalidate(); 
      break; 
    } 
} 

/** 
* @return 
*/ 
protected float calculateRadius(float x1, float y1, float x2, float y2) { 

    return (float) Math.sqrt(
      Math.pow(x1 - x2, 2) + 
        Math.pow(y1 - y2, 2) 
    ); 
} 

private void onDrawLine(Canvas canvas) { 

    float dx = Math.abs(mx - mStartX); 
    float dy = Math.abs(my - mStartY); 
    if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) { 
     canvas.drawLine(mStartX, mStartY, mx, my, mPaint); 
    } 
} 

private void onTouchEventLine(MotionEvent event) { 

    switch (event.getAction()) { 
     case MotionEvent.ACTION_DOWN: 
      isDrawing = true; 
      mStartX = mx; 
      mStartY = my; 
      invalidate(); 
      break; 
     case MotionEvent.ACTION_MOVE: 
      invalidate(); 
      break; 
     case MotionEvent.ACTION_UP: 
      isDrawing = false; 
      mCanvas.drawLine(mStartX, mStartY, mx, my, mPaint); 
      invalidate(); 
      break; 
    } 
} 

private void onTouchEventSmoothLine(MotionEvent event) { 

    switch (event.getAction()) { 
     case MotionEvent.ACTION_DOWN: 
      isDrawing = true; 
      mStartX = mx; 
      mStartY = my; 

      mPath.reset(); 
      mPath.moveTo(mx, my); 

      invalidate(); 
      break; 
     case MotionEvent.ACTION_MOVE: 

      float dx = Math.abs(mx - mStartX); 
      float dy = Math.abs(my - mStartY); 
      if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) { 
       mPath.quadTo(mStartX, mStartY, (mx + mStartX)/2, (my + mStartY)/2); 
       mStartX = mx; 
       mStartY = my; 
      } 
      mCanvas.drawPath(mPath, mPaint); 
      invalidate(); 
      break; 
     case MotionEvent.ACTION_UP: 
      isDrawing = false; 
      mPath.lineTo(mStartX, mStartY); 
      mCanvas.drawPath(mPath, mPaint); 
      mPath.reset(); 
      invalidate(); 
      break; 
    } 
} 

private void onDrawTriangle(Canvas canvas) { 

    if (countTouch < 3) { 
     canvas.drawLine(mStartX, mStartY, mx, my, mPaint); 
    } else if (countTouch == 3) { 
     canvas.drawLine(mx, my, mStartX, mStartY, mPaint); 
     canvas.drawLine(mx, my, basexTriangle, baseyTriangle, mPaint); 
    } 
} 

private void onTouchEventTriangle(MotionEvent event) { 

    switch (event.getAction()) { 
     case MotionEvent.ACTION_DOWN: 
      countTouch++; 
      if (countTouch == 1) { 
       isDrawing = true; 
       mStartX = mx; 
       mStartY = my; 
      } else if (countTouch == 3) { 
       isDrawing = true; 
      } 
      invalidate(); 
      break; 
     case MotionEvent.ACTION_MOVE: 
      invalidate(); 
      break; 
     case MotionEvent.ACTION_UP: 
      countTouch++; 
      isDrawing = false; 
      if (countTouch < 3) { 
       basexTriangle = mx; 
       baseyTriangle = my; 
       mCanvas.drawLine(mStartX, mStartY, mx, my, mPaint); 
      } else if (countTouch >= 3) { 
       mCanvas.drawLine(mx, my, mStartX, mStartY, mPaint); 
       mCanvas.drawLine(mx, my, basexTriangle, baseyTriangle, mPaint); 
       countTouch = 0; 
      } 
      invalidate(); 
      break; 
    } 
} 

public void clearDrawing() 
{ 
    setDrawingCacheEnabled(false); 
    onSizeChanged(width, height, width, height); 
    invalidate(); 

    setDrawingCacheEnabled(true); 
} 

/** 
* Getter of currentShape 
*/ 
public int getCurrentShape() { 
    return currentShape; 
} 

/** 
* Setter of currentShape 
*/ 
public void setCurrentShape(int currentShape) { 
    this.currentShape = currentShape; 
} 

}

+0

Et est un problème? Undoing formes? – CoolMind

Répondre

2

Toutes les formes peuvent être représentés par un chemin.

Vous avez probablement besoin de convertir toutes les formes dessinées avec drawCircle, drawArc, drawLine avec Path objets de la même forme. La classe Path possède toutes les méthodes dont vous avez besoin pour créer des formes prédéfinies. Exemples:

  • Chemin Circle: path.addCircle(float x, float y, float radius, Path.Direction dir)

  • Rectangle Chemin: path.addRect(float left, float top, float right, float bottom, Path.Direction dir)

Utilisez un quelque chose de classe comme celui-ci pour représenter une action de tirage de l'utilisateur:

public class DrawAction { 
    public Path path; 
    public Paint paint; 

    public DrawAction(Path path, Paint paint){ 
     this.path = path; 
     this.paint = paint; 
    } 
} 

Ensuite, enregistrez ces données dans une liste

//class property 
List<DrawAction> actionsList = new ArrayList<>(); 
...  
//add the path and the paint to a DrawAction object when the user 
//want to draw something 
actionsList.add(new DrawAction(path, paint)); 
invalidate(); 

Mettre en oeuvre votre méthode onDraw pour tirer tous les chemins dans la liste que

//draw all the paths in your onDraw() method 
@Override 
protected void onDraw(Canvas canvas) { 
    super.onDraw(canvas); 
    for (DrawAction actionToDraw : actionsList){ 
     canvas.drawPath(actionToDraw.path, actionToDraw.paint); 
    } 
} 

Maintenant, si vous avez besoin de refaire une action que vous pouvez supprimer le dernier élément de la liste et appelez le invalidate() pour demander l'affichage de la vue onDraw(), de cette manière, le dernier chemin ne sera plus tracé.

Il est évident que vous devez enregistrer l'opération d'annulation dans une autre liste pour être en mesure d'effectuer un redo, quelque chose comme ceci:

//class property 
List<DrawAction> removedPathList = new ArrayList<>(); 
if (actionsList.size() > 0){ 
    DrawAction undoAction = actionsList.get(actionsList.size() - 1); 
    removedPathList.add(undoAction); 
    actionsList.remove(undoAction); 
    invalidate(); 
} 

Espoir vous avoir indiqué dans la bonne direction :)

+0

Grande aide. Espérons que cela fonctionnerait –

+0

Peut s'il vous plaît partager comment dessiner rectangle, cercle en utilisant le chemin? –

+0

J'ai mis à jour la réponse en ajoutant 2 méthodes que vous pouvez utiliser pour créer un cercle Chemin et un rectangle Chemin – MatPag