在android画布上撤消功能

时间:2015-11-25 09:58:16

标签: android canvas undo

我所遵循的其他一些问题与我的相似,并以各种可能的方式实现了他们的答案,但这似乎对我的代码起作用。我接近解决方案但似乎缺少某些东西。请帮助,我要求不要将问题标记为重复。

这是mainActivity:

 public class MainActivity extends Activity implements View.OnClickListener                {

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

private Button btnUndo;

public DrawingView drawView;

//buttons
private ImageButton currPaint, drawBtn, eraseBtn, newBtn, saveBtn, opacityBtn;


//sizes
private float smallBrush, mediumBrush, largeBrush;

@Override
protected void onCreate(Bundle savedInstanceState) {


    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    drawView = (DrawingView) findViewById(R.id.drawing);

    //get the palette and first color button
    LinearLayout paintLayout = (LinearLayout) findViewById(R.id.paint_colors);
    currPaint = (ImageButton) paintLayout.getChildAt(0);
    currPaint.setImageDrawable(getResources().getDrawable(R.drawable.paint_pressed));

    //sizes from dimensions
    smallBrush = 10;
    mediumBrush = 20;
    largeBrush = 30;

    //draw button
    drawBtn = (ImageButton) findViewById(R.id.draw_btn);
    drawBtn.setOnClickListener(this);

    //set initial size
    drawView.setBrushSize(mediumBrush);

    //erase button
    eraseBtn = (ImageButton) findViewById(R.id.erase_btn);
    eraseBtn.setOnClickListener(this);

    //new button
    newBtn = (ImageButton) findViewById(R.id.new_btn);
    newBtn.setOnClickListener(this);

    //save button
    saveBtn = (ImageButton) findViewById(R.id.save_btn);
    saveBtn.setOnClickListener(this);

    //opacity
    opacityBtn = (ImageButton) findViewById(R.id.opacity_btn);
    opacityBtn.setOnClickListener(this);



  btnUndo = (Button) findViewById(R.id.btnUndo);
   btnUndo.setOnClickListener(new View.OnClickListener() {

       @Override
       public void onClick(View v) {
           drawView.undo();
       }
   });
}




@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

//user clicked paint
public void paintClicked(View view) {
    //use chosen color
    //set erase false
    drawView.setErase(false);
    drawView.setPaintAlpha(100);
    drawView.setBrushSize(drawView.getLastBrushSize());

    if (view != currPaint) {
        ImageButton imgView = (ImageButton) view;
        String color = view.getTag().toString();
        drawView.setColor(color);
        //update ui
        imgView.setImageDrawable(getResources().getDrawable(R.drawable.paint_pressed));
        currPaint.setImageDrawable(getResources().getDrawable(R.drawable.paint));
        currPaint = (ImageButton) view;
    }
}

@Override
public void onClick(View view) {

    if (view.getId() == R.id.draw_btn) {
        //draw button clicked
        final Dialog brushDialog = new Dialog(this);
        brushDialog.setTitle("Brush size:");
        brushDialog.setContentView(R.layout.brush_chooser);
        //listen for clicks on size buttons
        ImageButton smallBtn = (ImageButton) brushDialog.findViewById(R.id.small_brush);
        smallBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
              drawView.setErase(false);
                drawView.setBrushSize(smallBrush);
                drawView.setLastBrushSize(smallBrush);
                brushDialog.dismiss();
            }
        });
        ImageButton mediumBtn = (ImageButton) brushDialog.findViewById(R.id.medium_brush);
        mediumBtn.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
               drawView.setErase(false);
                drawView.setBrushSize(mediumBrush);
                drawView.setLastBrushSize(mediumBrush);
                brushDialog.dismiss();
            }
        });
        ImageButton largeBtn = (ImageButton) brushDialog.findViewById(R.id.large_brush);
        largeBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                drawView.setErase(false);
                drawView.setBrushSize(largeBrush);
                drawView.setLastBrushSize(largeBrush);
                brushDialog.dismiss();
            }
        });
        //show and wait for user interaction
        brushDialog.show();

    }


    else if (view.getId() == R.id.erase_btn) {
        //switch to erase - choose size
        final Dialog brushDialog = new Dialog(this);
        brushDialog.setTitle("Eraser size:");
        brushDialog.setContentView(R.layout.brush_chooser);
        //size buttons
        ImageButton smallBtn = (ImageButton) brushDialog.findViewById(R.id.small_brush);
        smallBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                drawView.setErase(true);
                drawView.setBrushSize(smallBrush);
                brushDialog.dismiss();
            }
        });
        ImageButton mediumBtn = (ImageButton) brushDialog.findViewById(R.id.medium_brush);
        mediumBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                drawView.setErase(true);
                drawView.setBrushSize(mediumBrush);
                brushDialog.dismiss();
            }
        });
        ImageButton largeBtn = (ImageButton) brushDialog.findViewById(R.id.large_brush);
        largeBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                drawView.setErase(true);
                drawView.setBrushSize(largeBrush);
                brushDialog.dismiss();
            }
        });
        brushDialog.show();
    } else if (view.getId() == R.id.new_btn) {
        //new button
        AlertDialog.Builder newDialog = new AlertDialog.Builder(this);
        newDialog.setTitle("New drawing");
        newDialog.setMessage("Start new drawing (you will lose the current drawing)?");
        newDialog.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                drawView.startNew();
                dialog.dismiss();
            }
        });
        newDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                dialog.cancel();
            }
        });
        newDialog.show();
    } else if (view.getId() == R.id.save_btn) {
        //save drawing
        AlertDialog.Builder saveDialog = new AlertDialog.Builder(this);
        saveDialog.setTitle("Save drawing");
        saveDialog.setMessage("Save drawing to device Gallery?");
        saveDialog.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                //save drawing
                drawView.setDrawingCacheEnabled(true);
                //attempt to save
                String imgSaved = MediaStore.Images.Media.insertImage(
                        getContentResolver(), drawView.getDrawingCache(),
                        UUID.randomUUID().toString() + ".png", "drawing");
                //feedback
                if (imgSaved != null) {
                    Toast savedToast = Toast.makeText(getApplicationContext(),
                            "Drawing saved to Gallery!", Toast.LENGTH_SHORT);
                    savedToast.show();
                } else {
                    Toast unsavedToast = Toast.makeText(getApplicationContext(),
                            "Oops! Image could not be saved.", Toast.LENGTH_SHORT);
                    unsavedToast.show();
                }
                drawView.destroyDrawingCache();
            }
        });
        saveDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                dialog.cancel();
            }
        });
        saveDialog.show();
    }

 /*  else if (view.getId() == R.id.btnUndo) {
        //undo drawing
        {
            //drawView.setErase(true);
            drawView.undo();

           /* if (paths.size() > 0) {
               // drawView.setErase(true);
                undonePaths.add(paths.remove(paths.size() - 1));
                view.invalidate();
            } else {
                Toast.makeText(getBaseContext(), "undo isnt working", Toast.LENGTH_SHORT).show();
            }*/


           else if (view.getId() == R.id.opacity_btn) {
               //launch opacity chooser
               final Dialog seekDialog = new Dialog(this);
               seekDialog.setTitle("Opacity level:");
               seekDialog.setContentView(R.layout.opacity_chooser);
               //get ui elements
               final TextView seekTxt = (TextView) seekDialog.findViewById(R.id.opq_txt);
               final SeekBar seekOpq = (SeekBar) seekDialog.findViewById(R.id.opacity_seek);
               //set max
               seekOpq.setMax(100);
               //show current level
               int currLevel = drawView.getPaintAlpha();
               seekTxt.setText(currLevel + "%");
               seekOpq.setProgress(currLevel);
               //update as user interacts
               seekOpq.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {

                   @Override
                   public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                       seekTxt.setText(Integer.toString(progress) + "%");
                   }

                   @Override
                   public void onStartTrackingTouch(SeekBar seekBar) {
                   }

                   @Override
                   public void onStopTrackingTouch(SeekBar seekBar) {
                   }

               });
               //listen for clicks on ok
               Button opqBtn = (Button) seekDialog.findViewById(R.id.opq_ok);
               opqBtn.setOnClickListener(new View.OnClickListener() {
                   @Override
                   public void onClick(View v) {
                       drawView.setPaintAlpha(seekOpq.getProgress());
                       seekDialog.dismiss();
                   }
               });
               //show dialog
               seekDialog.show();
           }
       }
   }

DrawingView.java:

(撤销功能位于此课程的底部)

public class DrawingView extends View{

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

private Path drawPath;
//drawing and canvas paint
private Paint drawPaint, canvasPaint;
//initial color
private int paintColor = 0xFF660000, paintAlpha = 255;
//canvas
private Canvas drawCanvas;
//canvas bitmap
private Bitmap canvasBitmap;
//brush sizes
private float brushSize, lastBrushSize;
//erase flag
private boolean erase = false;




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


}

private void setupDrawing() {

    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);
   // paths.add(drawPath);
}

@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);
    drawCanvas = new Canvas(canvasBitmap);
}

//draw the view - will be called after touch event
@Override
protected void onDraw(Canvas canvas) {
    for (Path path : paths) {
        canvas.drawPath(path, drawPaint);
    }
    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);
            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();
    //check whether color value or pattern name
    if (newColor.startsWith("#")) {
        paintColor = Color.parseColor(newColor);
        drawPaint.setColor(paintColor);
        drawPaint.setShader(null);
    } else {
        //pattern
        int patternID = getResources().getIdentifier(
                newColor, "drawable", "com.example.drawingfun");
        //decode
        Bitmap patternBMP = BitmapFactory.decodeResource(getResources(), patternID);
        //create shader
        BitmapShader patternBMPshader = new BitmapShader(patternBMP,
                Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
        //color and shader
        drawPaint.setColor(0xFFFFFFFF);
        drawPaint.setShader(patternBMPshader);
    }
}

//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();
}

//return current alpha
public int getPaintAlpha() {
    return Math.round((float) paintAlpha / 255 * 100);
}

//set alpha
public void setPaintAlpha(int newAlpha) {
    paintAlpha = Math.round((float) newAlpha / 100 * 255);
    drawPaint.setColor(paintColor);
    drawPaint.setAlpha(paintAlpha);
}

//define undo func
public void undo() {
    if (paths.size() > 0) {
        undonePaths.add(paths.remove(paths.size() - 1));
        invalidate();
    } else {

        Toast.makeText(getContext(), "undo isnt working wth", Toast.LENGTH_SHORT).show();
    }
}
}

1 个答案:

答案 0 :(得分:0)

我今天早些时候遇到了类似的问题,这是一张相当旧的票,所以我不确定你是否还有兴趣......不管别人怎么样。

我认为问题是你只使用一个路径实例 - 它有点奇怪,但路径不仅仅是A-B点

我认为你需要做的是在将它们放入你的收藏之前制作新的路径 - 塞尔文在他的评论中这样说。

例如,你可以这样做;

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:
        //Make a new instance of DrawPath
        drawPath = new Path();
        drawPath.moveTo(touchX, touchY);
        break;
    case MotionEvent.ACTION_MOVE:
        drawPath.lineTo(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;

}

当你进行路径休息时,我怀疑它正在清除所有被绘制的线 - 这是因为它们都是一条路径(尽管事实上有几个触摸事件已经成为它们)。

如果这不起作用,让我知道究竟是什么问题 - 线路没有出现等...