【问题标题】:android (multitouch) drawing app undone functionandroid(多点触控)绘图应用程序撤消功能
【发布时间】:2013-02-03 03:53:04
【问题描述】:

我正在开发一个绘图应用程序,onTouchEvents 是标准的,我想添加Undo() 函数来删除最后绘制的路径。

声明:

int thelastLineId=0;
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, Path> reservedpathMap; // for saving the paths being undone
private HashMap<Integer, Point> previousPointMap; // current Points

构造函数:

pathMap = new HashMap<Integer, Path>();
reservedpathMap = new HashMap <Integer,Path>(); // for storing path being undone
previousPointMap = new HashMap<Integer, Point>();

onDraw:

   @Override
   protected void onDraw(Canvas canvas) 
   {
       canvas.drawBitmap(bitmap, 0, 0, paintScreen);
       // for each path currently being drawn
       for (Integer key : pathMap.keySet()) 
            canvas.drawPath(pathMap.get(key), paintLine); // draw line     
   } 

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) 
      {       
          touchStarted(event.getX(actionIndex), event.getY(actionIndex), event.getPointerId(actionIndex));
      } 
      else if (action == MotionEvent.ACTION_UP) 
      {
          touchEnded(event.getPointerId(actionIndex));
      } 
      else 
      {
         touchMoved(event); 
      } 

      invalidate();
      return true; 
   } 

touchStarted:

   private void touchStarted(float x, float y, int lineID) // lineID represents how many fingers, 1 finger 1 line
   {      
      Path path; // used to store the path for the given touch id
      Point point; // used to store the last point in path

      // if there is already a path for lineID
      if (pathMap.containsKey(lineID)) 
      {
         path = pathMap.get(lineID); // get the Path
         path.reset(); // reset the Path because a new touch has started
         point = previousPointMap.get(lineID); // get Path's last point
      } 
      else 
      {
         path = new Path(); // create a new Path
         pathMap.put(lineID, path); // add the Path to Map
         point = new Point(); // create a new Point
         previousPointMap.put(lineID, point); // add the Point to the Map
      } 

      path.moveTo(x, y);
      point.x = (int) x;  
      point.y = (int) y;  
   } 

触摸移动:

   private void touchMoved(MotionEvent event) 
   {
      // for each of the pointers in the given MotionEvent
      for (int i = 0; i < event.getPointerCount(); i++) 
      {
         // get the pointer ID and pointer index
         int pointerID = event.getPointerId(i);
         int pointerIndex = event.findPointerIndex(pointerID);

         // if there is a path associated with the pointer
         if (pathMap.containsKey(pointerID)) 
         {
            float newX = event.getX(pointerIndex);
            float newY = event.getY(pointerIndex);

            // get the Path and previous Point associated with this pointer
            Path path = pathMap.get(pointerID);
            Point point = previousPointMap.get(pointerID);

            float deltaX = Math.abs(newX - point.x);
            float deltaY = Math.abs(newY - point.y);
            if (deltaX >= TOUCH_TOLERANCE || deltaY >= TOUCH_TOLERANCE) 
            {
               path.quadTo(point.x, point.y, ((newX + point.x)/2),((newY + point.y)/2));

               point.x = (int) newX ; 
               point.y = (int) newY ; 
         } 
      }      
   } 

touchEnded:

   private void touchEnded(int lineID)
   {
      Path path = pathMap.get(lineID); // get the corresponding Path
      bitmapCanvas.drawPath(path, paintLine); 
      path.reset();           
   }

撤消:

   public void undo()
   {
       Toast.makeText(getContext(), "undo button pressed" + thelastLineId, Toast.LENGTH_SHORT).show();

       Path path = pathMap.get(thelastLineId); 
       reservedpathMap.put(thelastLineId, path); // add the Path to reservedpathMap for later redo
       pathMap.remove(thelastLineId);   

       invalidate();          
   } 

问题:

我正在尝试使用如上所示的代码实现UNDO方法:尝试从HashMappathmap中删除thelastLindId键(并放入HashMap reservedpathMap以供稍后重做)这样当@987654335 @ 它将调用OnDraw() 并通过

for (Integer key : pathMap.keySet()) 
                canvas.drawPath(pathMap.get(key), paintLine); 

但是,按下撤消按钮可以启动“撤消已单击”的吐司,但最后绘制的线未能消失。

谁能给我一个 Undo() 和 Redo() 的线索?非常感谢提前!

【问题讨论】:

  • 你确定这段代码实际上是在删除最后一行吗?你有没有检查过你的 hashmap 的大小和里面的值?
  • 我刚刚添加了一个 Toast.makeText(getContext(), "touchEnded" + pathMap.size(), Toast.LENGTH_SHORT).show();在 TouchEnded 方法并尝试绘制以显示吐司。我发现当第一次用一根手指画时,它显示大小 = 1,但是,当用一根手指继续画第二行时,它仍然显示大小 = 1。然后我进一步尝试用 2 个手指画第三和第四同时它显示大小= 2。使用后 1 个手指绘制第 5 行大小显示 2。使用 3 个手指绘制第 6、7、8 行它显示大小 = 3。我真的不知道为什么。

标签: android canvas path hashmap


【解决方案1】:

我可以理解您想要实现的目标,您希望能够在画布上绘制线条,然后为您的项目添加 UNDO 功能。首先,我认为将路径添加到数组的那一刻应该是用户抬起手指时,在您的 touchEnded 方法中。其次,我真的不明白你解释的关于两个/三个手指的事情?你的画布支持多点触控吗?这是我之前在一些示例中使用的实现,用于在具有撤消实现的画布上绘图。希望它可以帮助您使事情更清楚:

public void onClickUndo () { 
if (paths.size()>0) { 
   undonePaths.add(paths.remove(paths.size()-1))
   invalidate();
 }
    else
     //toast the user 
}

public void onClickRedo (){
   if (undonePaths.size()>0) { 
       paths.add(undonePaths.remove(undonePaths.size()-1)) 
       invalidate();
   } 
   else 
     //toast the user 
}

这里是你的触摸方法的等价物:

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
}

@Override
protected void onDraw(Canvas canvas) {            

    for (Path p : paths){
        canvas.drawPath(p, mPaint);
    }

}

private float mX, mY;
private static final float TOUCH_TOLERANCE = 0;

private void touch_start(float x, float y) {
    mPath.reset();
    mPath.moveTo(x, y);
    mX = x;
    mY = y;
}
private void touch_move(float x, float y) {
    float dx = Math.abs(x - mX);
    float dy = Math.abs(y - mY);
    if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
        mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
        mX = x;
        mY = y;
    }
}
private void touch_up() {
    mPath.lineTo(mX, mY);
    // commit the path to our offscreen
    mCanvas.drawPath(mPath, mPaint);
    // kill this so we don't double draw            
    mPath = new Path();
    paths.add(mPath);
}

从这里可以看出,paths 是我存储路径的数组列表。如果您告诉我为什么需要将路径放在 hashmap 中,也许我会更有帮助。

【讨论】:

  • 非常感谢您的详细解答!对于我上面提到的 2 或 3 根手指,是的,绘图视图支持多点触控,并且当同时使用 2 根手指时,toast 报告 hashmap 的大小 = 2,如果同时使用 3 根手指绘图,则报告为 3。之后如果使用 1 根手指,它仍然会显示 size =3
  • 我刚刚同时使用您上面的代码形成了一个非多点触控绘图代码。使用路径数组一切正常。然而,当我如上所示执行撤消操作时,它不起作用并出现了 2 个问题,如 stackoverflow.com/questions/14960152/… 所示,只是想知道您是否对此有任何线索 =) 非常感谢!!
猜你喜欢
  • 2015-08-12
  • 2017-07-19
  • 2013-02-04
  • 2015-05-19
  • 2018-09-01
  • 2014-12-21
  • 2013-01-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多