android canvas删除以前绘制的路径

时间:2013-02-13 07:08:21

标签: android canvas bitmap

我正在制作一个绘图应用,并希望实现一个撤消功能来删除之前的绘制路径。

编码:

private HashMap<Integer, Path> pathMap; // current Paths being drawn
private HashMap<Integer, Point> previousPointMap; // current Points
private Bitmap bitmap; // drawing area for display or saving
private Canvas bitmapCanvas; // used to draw on bitmap
private Paint paintScreen; // use to draw bitmap onto screen
private Paint paintLine; // used to draw lines onto bitmap

public DrawView(Context context, AttributeSet attrs) 
{
     super(context, attrs); // pass context to View's constructor
     this.context_new=context;

      paintScreen = new Paint(); // used to display bitmap onto screen

      // set the initial display settings for the painted line
      paintLine = new Paint();
      paintLine.setAntiAlias(true); // smooth edges of drawn line
      paintLine.setColor(Color.BLACK); // default color is black
      paintLine.setStyle(Paint.Style.STROKE); // solid line
      paintLine.setStrokeWidth(5); // set the default line width
      paintLine.setStrokeCap(Paint.Cap.ROUND); // rounded line ends
      pathMap = new HashMap<Integer, Path>();
      previousPointMap = new HashMap<Integer, Point>();
} // end DrawView constructor

@Override
protected void onDraw(Canvas canvas)  
{
    canvas.drawBitmap(bitmap, 0, 0, paintScreen); 
    for (Integer key : pathMap.keySet()) 
    canvas.drawPath(pathMap.get(key), paintLine);
} 

// called when the user finishes a touch    
   private void touchEnded(int lineID)   
   {
      Path path = pathMap.get(lineID); // get the corresponding Path
      bitmapCanvas.drawPath(path, paintLine); // draw to bitmapCanvas
      path.reset(); // reset the Path
      rememberLineId = lineID;
   } // end method touch_ended

//undo       
   private void undo()
   {
      Path path = pathMap.get(rememberLineId); // get the corresponding Path
      pathMap.remove(rememberLineId);
      bitmapCanvas.clearPath(path, paintLine); 
      path.reset(); // reset the Path
   } 

问题:

然而,这个方法似乎没有bitmapCanvas.clearPath?如果那么它怎么可能被修改?

代码修订:

声明:

private Bitmap bitmap; // drawing area for display or saving
private Canvas bitmapCanvas; // used to draw on bitmap
private Paint paintScreen; // use to draw bitmap onto screen
private Paint paintLine; // used to draw lines onto bitmap
private HashMap<Integer, Path> pathMap; // current Paths being drawn
private HashMap<Integer, Point> previousPointMap; // current Points

private Bitmap bitmapBackup; 

OnSizeChanged

@Override
public void onSizeChanged(int w, int h, int oldW, int oldH)
{ 
   super.onSizeChanged(w, h, oldW, oldH);
   DoodlzViewWidth = w;    
   DoodlzViewHeight = h;

   bitmapBackup = Bitmap.createBitmap(getWidth(), DoodlzViewHeight, Bitmap.Config.ARGB_8888);     
   bitmap =       Bitmap.createBitmap(getWidth(), DoodlzViewHeight, Bitmap.Config.ARGB_8888);

   bitmapCanvas = new Canvas(bitmap);
   bitmap      .eraseColor(Color.WHITE); // erase the BitMap with white 
   bitmapBackup.eraseColor(Color.WHITE); 
} 

FirsttoBackup方法,将在以下TouchedStart执行时调用

public void firsttobackup()
{ 
   bitmapBackup=bitmap;
       Toast message = Toast.makeText(getContext(), "backuped 123", Toast.LENGTH_SHORT);
   message.show(); //THIS TOAST CAN BE SUCESSFULLY PRESENTED when touching screen starting to draw
} 

的OnDraw

@Override
protected void onDraw(Canvas canvas) 
{
canvas.drawBitmap(bitmap, 0, 0, paintScreen); 
    for (Integer key : pathMap.keySet()) 
     canvas.drawPath(pathMap.get(key), paintLine); 

}

的onTouchEvent

@Override
public boolean onTouchEvent(MotionEvent event) 
{        
  int action = event.getActionMasked(); // event type 
  int actionIndex = event.getActionIndex(); // pointer (i.e., finger)

  if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN) 
  {
      firsttobackup(); //TOAST CAN SHOW "BACKUP 123"

      touchStarted(event.getX(actionIndex), event.getY(actionIndex), 
        event.getPointerId(actionIndex));
  }

撤消:用户按下撤消按钮将调用此

public void undo()
{
  bitmap = bitmapBackup.copy(Bitmap.Config.ARGB_8888, true);
  bitmapCanvas = new Canvas(bitmap);        
}  

问题修订:

现在使用方法firsttobackup(),以便bitmapBackup在执行OnTouchEvent touchStarted时设置=位图。我已经在其中放了一个吐司,当用户按下屏幕并开始绘制时,可以提供“备份123”。

当用户点击撤销按钮时,它将调用undo方法,但现在按下撤消按钮,无法看到任何操作......为什么?

谢谢!

6 个答案:

答案 0 :(得分:8)

我认为最简单的方法是使用2个位图(1个额外的备份位图用于恢复以前的状态)。

在开始新绘图之前,您需要保存位图的先前状态。

以下是我修改代码的方法:

  private HashMap<Integer, Path> pathMap; // current Paths being drawn
  private HashMap<Integer, Point> previousPointMap; // current Points
  private Bitmap bitmap; // drawing area for display or saving
  private Bitmap bitmapBackup; 
  private Canvas bitmapCanvas; // used to draw on bitmap
  private Canvas bitmapBackupCanvas; 


  // remember last bitmap before new drawings...    
     private void touchStarted()   
     {
        bitmapBackupCanvas.drawBitmap(bitmap, 0, 0, null);
     } 
  // called when the user finishes a touch    
     private void touchEnded(int lineID)   
     {
        Path path = pathMap.get(lineID); // get the corresponding Path
        bitmapCanvas.drawPath(path, paintLine); // draw to bitmapCanvas
        path.reset(); // reset the Path
        rememberLineId = lineID;
     } // end method touch_ended

  //undo       
     private void undo()
     {
        Path path = pathMap.get(rememberLineId); // get the corresponding Path
        pathMap.remove(rememberLineId);
        bitmapCanvas.drawBitmap(bitmapBackup, 0, 0, null); // restore from backup
        path.reset(); // reset the Path
     } 

答案 1 :(得分:4)

这是一篇旧文章,但我也在寻找该问题的答案。我对为该帖子选择的答案不满意,此后我自己找到了一个。 实际上,我认为拥有完整的位图作为备份并不是一个很好的内存管理方法,它将限制我们可以执行的撤消步骤。

我相信更好的解决方案是:

要在课程中添加一堆路径

private Stack<Path> m_pathHistory = new Stack<Path>();

画布和画笔旁边(跳过初始化):

private Canvas m_drawingCanvas;
private Paint m_paint;

然后,每完成一次笔画(在修饰事件中),在撤消历史记录中添加路径的“克隆”:

m_pathHistory.Push(new Path(currentPath));

这是撤消功能:

public void Undo()
{
    if(m_pathHistory.Count > 0)
    {
        m_pathHistory.Pop(); // Remove the last path from the history

        m_drawingCanvas.DrawColor(Color.Transparent, PorterDuff.Mode.Clear); // Clear the canvas with a transparent color

        // Draw the paths which are still in the history
        foreach (Path p in m_pathHistory)
        {
            m_drawingCanvas.DrawPath(p, m_paint);
        }
     }
}

要存储在内存中的路径比完整的位图要小得多,因此我们可以拥有更大的历史记录。

答案 2 :(得分:1)

use path.reset()in the MotionEvent.ACTION_DOWN event of OnTouchEvent() method.

@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            mPath.reset();
            invalidate();
            break;
    }
    return true;

}

答案 3 :(得分:0)

答案 4 :(得分:0)

乍一看,我发现以下问题:

  

Pathpaths添加到Path后,您就可以了   一旦你撤消就会遇到问题:你正在弹出那个空的   Path首先,使第一次撤消似乎不起作用。如果你画画   进入paths,它不会添加到Path。解决方案是添加   在创建新路径之前,touch_up()已完成paths.add(mPath); 个路径。

即删除

touch_up()

来自构造函数,并在mPath = new Path(); paths.add(mPath); 中更改

paths.add(mPath);
mPath = new Path();

canvas.drawPath(mPath, mPaint);

您还需要添加

for
onDraw() Path循环后

,以便绘制正在进行中的undonePaths

当用户再次开始绘图时,您不会清空{{1}}。

答案 5 :(得分:0)

如果您使用PorterDuffXfermode,请将视图保存到bitmapBackup, 而不是以前的位图

public void undo (){
    bitmap.eraseColor(getDrawingCacheBackgroundColor());
    mCanvas.drawBitmap(bitmapBackup, 0, 0, null);
    invalidate();
    mPath.reset();
    undofresh=true;
}


private void touch_start(float x, float y) {
    View v1 = this;
    v1.setDrawingCacheEnabled(true);
    this.bitmapBackup = Bitmap.createBitmap(v1.getDrawingCache());
    v1.setDrawingCacheEnabled(false);
}