Android Canvas Redo и Undo Operation

Я работаю над рисованием project.my-кода, который отлично работает, но, перетаскивание холста и отмена операции не работают отлично. Работа в режиме не работает. Прекрасная работа и повторные операции не работают отлично. Отмена операции удаляет пути из путей, а также сохраняет в unopaths arraylist и redo Операция удаляет последний элемент из нераспакованного arraylist и сохраняет на пути arraylist.

Вот мой код:

import java.util.ArrayList; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; public class DrawView extends View implements OnTouchListener { private Canvas mCanvas; private Path mPath; private Paint mPaint; private ArrayList<Path> paths = new ArrayList<Path>(); private ArrayList<Path> undonePaths = new ArrayList<Path>(); private Bitmap im; public DrawView(Context context) { super(context); setFocusable(true); setFocusableInTouchMode(true); this.setOnTouchListener(this); mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setDither(true); mPaint.setColor(0xFFFFFFFF); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeJoin(Paint.Join.ROUND); mPaint.setStrokeCap(Paint.Cap.ROUND); mPaint.setStrokeWidth(6); mCanvas = new Canvas(); mPath = new Path(); paths.add(mPath); im=BitmapFactory.decodeResource(context.getResources(),R.drawable.ic_launcher); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); } @Override protected void onDraw(Canvas canvas) { //mPath = new Path(); //canvas.drawPath(mPath, mPaint); for (Path p : paths){ canvas.drawPath(p, mPaint); } } private float mX, mY; private static final float TOUCH_TOLERANCE = 4; 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); } 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 public boolean onTouch(View arg0, 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; } } 

Этот рисунок кода работает отлично и не работает отлично отменить и повторить операцию.

Что не так в моем коде!

Как решить эту проблему, может кто-нибудь помочь мне с большой оценкой.

Вот мой исходный код

http://www.4shared.com/rar/8PQQEZdH/test_draw.html

Благодаря…

ОБНОВЛЕНО:

Наконец, моя проблема была решена, вот мой класс рисования:

 import java.util.ArrayList; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; public class DrawView extends View implements OnTouchListener { private Canvas mCanvas; private Path mPath; private Paint mPaint; private ArrayList<Path> paths = new ArrayList<Path>(); private ArrayList<Path> undonePaths = new ArrayList<Path>(); private Bitmap im; public DrawView(Context context) { super(context); setFocusable(true); setFocusableInTouchMode(true); this.setOnTouchListener(this); mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setDither(true); mPaint.setColor(0xFFFFFFFF); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeJoin(Paint.Join.ROUND); mPaint.setStrokeCap(Paint.Cap.ROUND); mPaint.setStrokeWidth(6); mCanvas = new Canvas(); mPath = new Path(); im=BitmapFactory.decodeResource(context.getResources(),R.drawable.ic_launcher); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); } @Override protected void onDraw(Canvas canvas) { //mPath = new Path(); //canvas.drawPath(mPath, mPaint); for (Path p : paths){ canvas.drawPath(p, mPaint); } canvas.drawPath(mPath, mPaint); } private float mX, mY; private static final float TOUCH_TOLERANCE = 4; 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; } } 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 paths.add(mPath); mPath = new Path(); } 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 public boolean onTouch(View arg0, 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; } } 

Это код работает отлично …!

Solutions Collecting From Web of "Android Canvas Redo и Undo Operation"

На первый взгляд я вижу следующие проблемы:

  • Путем добавления пустого Path к paths как только вы это сделаете, у вас возникнет проблема, как только вы отмените отмену: сначала вы выходите на этот пустой 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() , чтобы нарисовать onDraw() Path .

  • Вы не undonePaths когда пользователь снова начинает рисовать.

Пожалуйста, проверьте ниже код, который он работает.

 package com.testpath; import java.util.ArrayList; import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import android.os.Bundle; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnTouchListener; import android.widget.Button; import android.widget.LinearLayout; public class TesUndoPaintActivity extends Activity { /** Called when the activity is first created. */ LinearLayout linearLayout2; private ArrayList<Path> undonePaths = new ArrayList<Path>(); private ArrayList<Path> paths = new ArrayList<Path>(); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); linearLayout2 = (LinearLayout) findViewById(R.id.linearLayout2); final DrawingPanel dp = new DrawingPanel(this); linearLayout2.addView(dp); ((Button) findViewById(R.id.button1)) .setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub if (paths.size() > 0) { undonePaths.add(paths .remove(paths.size() - 1)); dp.invalidate(); } } }); ((Button) findViewById(R.id.button2)) .setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub if (undonePaths.size()>0) { paths.add(undonePaths.remove(undonePaths.size()-1)); dp.invalidate(); } } }); } public class DrawingPanel extends View implements OnTouchListener { private Canvas mCanvas; private Path mPath; private Paint mPaint, circlePaint, outercirclePaint; // private ArrayList<Path> undonePaths = new ArrayList<Path>(); private float xleft, xright, xtop, xbottom; public DrawingPanel(Context context) { super(context); setFocusable(true); setFocusableInTouchMode(true); this.setOnTouchListener(this); circlePaint = new Paint(); mPaint = new Paint(); outercirclePaint = new Paint(); outercirclePaint.setAntiAlias(true); circlePaint.setAntiAlias(true); mPaint.setAntiAlias(true); mPaint.setColor(0xFFFFFFFF); outercirclePaint.setColor(0x44FFFFFF); circlePaint.setColor(0xAADD5522); outercirclePaint.setStyle(Paint.Style.STROKE); circlePaint.setStyle(Paint.Style.FILL); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeJoin(Paint.Join.ROUND); mPaint.setStrokeCap(Paint.Cap.ROUND); mPaint.setStrokeWidth(6); outercirclePaint.setStrokeWidth(6); mCanvas = new Canvas(); mPath = new Path(); paths.add(mPath); } public void colorChanged(int color) { mPaint.setColor(color); } @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); } @Override public boolean onTouch(View arg0, MotionEvent event) { float x = event.getX(); float y = event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: // if (x <= cx+circleRadius+5 && x>= cx-circleRadius-5) { // if (y<= cy+circleRadius+5 && cy>= cy-circleRadius-5){ // paths.clear(); // return true; // } // } 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; } } } 

И ниже XML-файла.

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <LinearLayout android:id="@+id/linearLayout1" android:layout_width="match_parent" android:layout_height="wrap_content" > <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Undo" /> <Button android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Redo" /> </LinearLayout> <LinearLayout android:id="@+id/linearLayout2" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > </LinearLayout> </LinearLayout> 

Пожалуйста, проверь это.

проблема

Путь отображается только тогда, когда вы закончите рисовать его, что не дает пользователю понять, что он рисует

Решение

 @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); for (Path p : paths){ canvas.drawPath(p, mPaint); } //Draw path along with the finger canvas.drawPath(mPath, mPaint); } 

Добавьте canvas.drawPath(mPath,mPaint) в onDraw() чтобы пользователь получил ощущение фактической живописи на холсте.