【问题标题】:Android: Painting app with eraser not workingAndroid:带橡皮擦的绘画应用程序不起作用
【发布时间】:2014-10-29 17:02:33
【问题描述】:

我正在开发一个具有撤销/重做功能的绘画应用程序,并想添加橡皮擦功能。

MainActivity 代码

case R.id.undoBtn:          
     doodleView.onClickUndo();          
     break;

case R.id.redoBtn:          
     doodleView.onClickRedo();          
     break;

case R.id.eraserBtn:            
     Constants.mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); break; 

绘图视图

// Drawing Part    
    private Bitmap mBitmap;   
    private Paint  mBitmapPaint;
    private Canvas mCanvas; 
    private Path   mPath; 
    private int selectedColor = Color.BLACK;
    private int selectedWidth = 5;

    private ArrayList<Path> paths = new ArrayList<Path>();
    private ArrayList<Path> undonePaths = new ArrayList<Path>();
    private Map<Path, Integer> colorsMap = new HashMap<Path, Integer>();
    private Map<Path, Integer> widthMap = new HashMap<Path, Integer>();

    private float mX, mY;
    private static final float TOUCH_TOLERANCE = 4; 
    Context context_new;

   public DoodleView(Context c, AttributeSet attrs) 
   {
       super(c, attrs);
       context_new = c;    
       setFocusable(true);
       setFocusableInTouchMode(true);
       setLayerType(View.LAYER_TYPE_SOFTWARE, null); // for solely removing the black eraser

       mPath = new Path(); 
       mCanvas = new Canvas();  
       mBitmapPaint = new Paint(Paint.DITHER_FLAG);   

       Constants.mPaint = new Paint();
       Constants.mPaint.setAntiAlias(true); // smooth edges of drawn line
       Constants.mPaint.setDither(true);
       Constants.mPaint.setColor(Color.BLACK); // default color is black
       Constants.mPaint.setStyle(Paint.Style.STROKE); // solid line
       Constants.mPaint.setStrokeJoin(Paint.Join.ROUND);
       Constants.mPaint.setStrokeWidth(20); // set the default line width
       Constants.mPaint.setStrokeCap(Paint.Cap.ROUND); // rounded line ends 
       Constants.mPaint.setXfermode(null);
       Constants.mPaint.setAlpha(0xFF);
   } 

   @Override
   public void onSizeChanged(int w, int h, int oldW, int oldH)
   {
       super.onSizeChanged(w, h, oldW, oldH);
       mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);

      Constants.DRAW_W = w;
      Constants.DRAW_H = h;
      Log.d("TAG", "onSizeChanged!!!" + Constants.DRAW_W + Constants.DRAW_H + Constants.SCREEN_W + Constants.SCREEN_H);   
      // bitmap.eraseColor(Color.WHITE); // erase the BitMap with white    
   }   

   @Override
   protected void onDraw(Canvas canvas) 
   {
       canvas.drawBitmap(mBitmap, 0, 0, null); // draw the background screen

       for (Path p : paths)
       {
           Constants.mPaint.setColor(colorsMap.get(p));
           Constants.mPaint.setStrokeWidth(widthMap.get(p));
           canvas.drawPath(p, Constants.mPaint);           
       }       
       Constants.mPaint.setColor(selectedColor);
       Constants.mPaint.setStrokeWidth(selectedWidth);
       canvas.drawPath(mPath, Constants.mPaint);                   
   } 

   @Override
   public boolean onTouchEvent(MotionEvent event) 
   {          
          float x = event.getX();
          float y = event.getY();

          switch (event.getAction())
          {
              case MotionEvent.ACTION_DOWN:
                   touch_start(x, y);
                   invalidate();
                   break;
              case MotionEvent.ACTION_MOVE:
                   touch_move(x, y);
                   invalidate();
                   break;
              case MotionEvent.ACTION_UP:
                   touch_up();
                   invalidate();
                   break;
          }
          return true;
    }

   private void touch_start(float x, float y) 
   {
       undonePaths.clear();
       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;

           startdrawing = true;
       }
   }

   private void touch_up() 
   {
       mPath.lineTo(mX, mY);      
       mCanvas.drawPath(mPath, Constants.mPaint); 
       paths.add(mPath);
       colorsMap.put(mPath,selectedColor);
       widthMap.put(mPath,selectedWidth);
       mPath = new Path(); 
   }

   public void onClickUndo() 
   { 
       if (paths.size()>0) 
        { 
           undonePaths.add(paths.remove(paths.size()-1));
           invalidate();
        }      
       else Toast.makeText(getContext(), R.string.toast_nothing_to_undo, Toast.LENGTH_SHORT).show();  
    }

   public void onClickRedo()
   {
       if (undonePaths.size()>0) 
       { 
           paths.add(undonePaths.remove(undonePaths.size()-1)); 
           invalidate();
       } 
       else 
           Toast.makeText(getContext(), R.string.toast_nothing_to_redo, Toast.LENGTH_SHORT).show(); 
    }  

   public void setDrawingColor(int color)
   {       
       selectedColor = color;
       Constants.mPaint.setColor(color);
   } 

   public int getDrawingColor()
   {
      return Constants.mPaint.getColor();
   } 

问题:

正常绘画和撤消/重做可以完美执行。但是,橡皮擦不起作用。

  1. 按下(touch_start)橡皮擦按钮并触摸屏幕后,之前绘制的所有线条立即变黑。

  2. touch_move 上使用橡皮擦时,即使在CLEAR 模式下,橡皮擦本身也会画黑线。

  3. touch_up 上,所有其他绘制的线都保持为黑色。 “擦除”区域也是黑色的。然而,当随后绘制一条新路径时,原来的线变成了原来的颜色,被橡皮擦“擦除”的区域变成了最后选择的颜色,路径保留在视图中。

橡皮擦上的代码怎么写得好? (保持撤消/重做)

提前非常感谢!

【问题讨论】:

    标签: android colors paint eraser


    【解决方案1】:

    很难回答你的问题,但是。我将按如下方式实现擦除功能:

    擦除功能将通过简单的白色路径。所以擦除模式意味着你正在绘制比绘制路径更宽的白色路径。这样您甚至可以选择橡皮擦的宽度,并且撤消/重做功能将保持不变。

    【讨论】:

    • 谢谢卢博。然而,在以后的开发中,油漆的背景将不再是一个白板,而是将图像加载到背景中。这样白线就不可能充当橡皮擦
    • 即使在这种情况下也可以这样做。您将有两张图像,一张作为背景,第二张将是透明的线条。擦除将是唯一的颜色,这将使所有像素透明。然后在 draw 方法中,您首先绘制背景,然后再绘制路径。
    • 我知道你的意思。底部将是一个图像视图,而顶部将是具有透明背景的绘图视图。然后橡皮擦在画线上方画出透明线以覆盖画线,以假装擦除效果。但我试过了,它不起作用。 “擦除”线条被绘制到其他线条上而不是擦除,因此仅用透明颜色在绘制的线条上绘制,并且不会消除绘制的线条。我用白色替换了透明颜色,代码正在执行
    • 所以使用这个小技巧:绘制的白色是 RGB(254,254,254),擦除颜色是 RGB(255,255,255)。然后在绘制路径之前,您会将所有 RGB(255,255,255) 像素转换为透明。如果你想要谷歌的例子:java android convert white color to transparent。我找到了这个:javaworld.com/article/2074105/core-java/…
    【解决方案2】:

    试试这个解决方案 - 也适用于撤消/重做:

       private float blur = 0F;
    
        case R.id.eraserBtn:            
             Constants.mPaint.setColor(Color.WHITE); // or whatever color to match canvas color
             Constants.mPaint.setShadowLayer(this.blur, 0F, 0F, Color.WHITE);
    

    有了这个方案,就不用设置了:

     Constants.mPaint.setXfermode(null);
    

    【讨论】:

    • 嗨,我已经尝试过但不能用作橡皮擦,而是在绘图线下方有一个白色阴影(因此,一旦按下橡皮擦按钮,之前绘制的线就会出现)
    • 我只是找不到这样一个基本的绘画应用程序的示例代码,包括画线、橡皮擦和撤消/重做功能。
    • @pearmak 在这种情况下,我建议使用单独的橡皮擦 Path() 并为其绘制画布的颜色。您可以以相同的方式对橡皮擦 Path() 实施撤消/重做。注意:此解决方案适用于画布,而不适用于图像背景。
    【解决方案3】:

    用 samsung spen sdk 试试这种类型的应用程序,所有这些功能都在那里得到了简化。 SPen Sdk Tutorial

    将您的擦除油漆颜色设置为您的背景颜色。

    【讨论】:

    • 感谢您的回复!但是三星sdk可以在其他品牌的手机上使用吗?比如LG、索尼?并且由于背景要加载图像,因此没有设置橡皮擦的背景颜色。
    【解决方案4】:

    // 请使用这是擦除的概念。这是有效且经过测试的。

    public void addErasure(){
            drawView.setErase(true);
            drawView.setBrushSize(20);
        }
    
        public void addPencil(){
            drawView.setErase(false);
            drawView.setBrushSize(20);
            drawView.setLastBrushSize(20);
        }
    /// this my drawing view. you can add this view into your main layout.
    
        public class DrawingView extends View {
    
            //drawing path
            private Path drawPath;
            //drawing and canvas paint
            private Paint drawPaint, canvasPaint;
            //initial color
            private int paintColor = 0xFF660000;
            //canvas
            private Canvas drawCanvas;
            //canvas bitmap
            private Bitmap canvasBitmap;
            //brush sizes
            private float brushSize, lastBrushSize;
            //erase flag
            private boolean erase=false;
    
            private boolean isFirstTime = false;
    
            public DrawingView(Context context, AttributeSet attrs){
                super(context, attrs);
                //setBackgroundColor(Color.CYAN);
                setupDrawing();
            }
    
            //setup drawing
            private void setupDrawing(){
    
                //prepare for drawing and setup paint stroke properties
                brushSize = getResources().getInteger(R.integer.medium_size);
                lastBrushSize = brushSize;
                drawPath = 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);
                //canvasPaint.setColor(Color.GREEN);
            }
    
            //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);
                Bitmap canvasBackGroundBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
                canvasBackGroundBitmap = getResizedBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.pop_up_big_bg),h,w);
        //      drawCanvas = new Canvas(canvasBackGroundBitmap);
        //      drawCanvas.drawColor(Color.GREEN);
                setBackgroundDrawable(new BitmapDrawable(canvasBackGroundBitmap));
    
                drawCanvas = new Canvas(canvasBitmap);
            }
    
            public static Bitmap getResizedBitmap(Bitmap bm, int newHeight, int newWidth) {
                int width = bm.getWidth();
                int height = bm.getHeight();
                float scaleWidth = ((float) newWidth) / width;
                float scaleHeight = ((float) newHeight) / height;
                // CREATE A MATRIX FOR THE MANIPULATION
                Matrix matrix = new Matrix();
                // RESIZE THE BIT MAP
                matrix.postScale(scaleWidth, scaleHeight);
    
                // "RECREATE" THE NEW BITMAP
                Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false);
                return resizedBitmap;
            }
    
            //draw the view - will be called after touch event
            @Override
            protected void onDraw(Canvas canvas) {
                canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
                canvas.drawPath(drawPath, 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.moveTo(touchX, touchY);
                    break;
                case MotionEvent.ACTION_MOVE:
                    drawPath.lineTo(touchX, touchY);
                    drawCanvas.drawPath(drawPath, drawPaint);
                    drawPath.reset();
                    drawPath.moveTo(touchX, touchY);
                    break;
                case MotionEvent.ACTION_UP:
                    //drawPath.lineTo(touchX, touchY);
                    //drawCanvas.drawPath(drawPath, drawPaint);
                    drawPath.reset();
                    break;
                default:
                    return false;
                }
                //redraw
                invalidate();
                return true;
    
            }
    
    
    
    
    
            //update color
            public void setColor(String newColor){
                invalidate();
                paintColor = Color.parseColor(newColor);
                drawPaint.setColor(paintColor);
            }
    
            //set brush size
            public void setBrushSize(float newSize){
                float pixelAmount = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 
                        newSize, getResources().getDisplayMetrics());
                brushSize=pixelAmount;
                drawPaint.setStrokeWidth(brushSize);
            }
    
            //get and set last brush size
            public void setLastBrushSize(float lastSize){
                lastBrushSize=lastSize;
            }
            public float getLastBrushSize(){
                return lastBrushSize;
            }
    
            //set erase true or false
            public void setErase(boolean isErase){
                erase=isErase;
                if(erase) {
                    drawPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
                }else {
                    drawPaint.setXfermode(null);
                }
            }
    
            //start new drawing
            public void startNew(){
                drawCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
                invalidate();
            }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-07-15
      • 1970-01-01
      • 2014-05-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-16
      相关资源
      最近更新 更多