Android: приложение рисования с ластиком не работает
Я работаю над приложением рисования с функцией отмены / повтора и хотел бы добавить функцию ластика.
Код для 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;
DrawView
// 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();
}
Вопрос:
Нормальная покраска и отмена / повтор могут быть выполнены отлично. Однако ластик не работает.
После нажатия (
touch_start
) кнопку ластика и коснитесь экрана, все предыдущие нарисованные линии сразу станут черными.При использовании ластика на
touch_move
Сам ластик рисует черные линии, даже еслиCLEAR
Режим.на
touch_up
Все остальные нарисованные линии поддерживаются черным цветом. "Стираемая" область также была черного цвета. Однако при последующем рисовании нового контура исходная линия изменяет свой первоначальный цвет, область, "стертая" ластиком, меняет свой цвет на последний выбранный цвет, а контуры остаются в представлении.
Как правильно написать код на ластике? (сохраняя отмену / повтор)
Заранее большое спасибо!
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();
}
}
Попробуйте этот тип приложения с samsung spen sdk, все эти функции там упрощены. SPen Sdk Tutorial
или же
Сделайте ваш стереть краску в цвет фона.
Трудно ответить на твой вопрос, но. Я бы реализовал функцию стирания следующим образом:
Функция стирания будет простым белым путем. Таким образом, режим стирания означает, что вы рисуете белый путь, который будет шире, чем путь рисования. Таким образом, вы сможете выбрать даже ширину ластика, и функция отмены / возврата останется прежней.
Попробуйте это решение - прекрасно работает и с отменой / повторением:
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);