Android Help
Android Help

Reputation: 271

How to perform Undo and Redo operation on canvas in android

How can I perform the Undo/Redo operation on canvas . And my code is blow and i am not performing the these two operation .In the main class paint is performing by this reason am not perform the undo redo operation.

public class MainActivity extends Activity implements OnClickListener{

MyView mView;
private Path mPath;
Button btnUndo,btnRedo;
FrameLayout frmLayout;
private Paint       mPaint;
private MaskFilter  mEmboss;
Bitmap  mBitmap;
int bckcolor=0xffffffff;
final Context context = this;

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

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mView = new MyView(this);
    setContentView(R.layout.activity_main);

    btnUndo=(Button)findViewById(R.id.Undo);
    btnRedo=(Button)findViewById(R.id.Redo);

    btnUndo.setOnClickListener(this);
    btnRedo.setOnClickListener(this);

    frmLayout=(FrameLayout)findViewById(R.id.frameLayout);
    frmLayout.addView(mView,LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);  

    mPaint = new Paint();
    mPath=new Path();
    mPaint.setAntiAlias(true);
    mPaint.setDither(true);
    mPaint.setColor(0xFF000000);
    mPaint.setStyle(Paint.Style.STROKE);
    mPaint.setStrokeJoin(Paint.Join.ROUND);
    mPaint.setStrokeCap(Paint.Cap.ROUND);
    mPaint.setStrokeWidth(5);
    new Canvas();       
   paths.add(mPath);

    mEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 },0.4f, 6, 3.5f);
    new BlurMaskFilter(8, BlurMaskFilter.Blur.NORMAL);
}

@Override
public void onClick(View v) {
    // TODO Auto-generated method stub


    switch (v.getId()) {

   case R.id.Undo:

       if (paths.size()>0) 
        { 
           undonePaths.add(paths.remove(paths.size()-1));
           mView.invalidate();
           Toast.makeText(getApplicationContext(), "Undo", 1000).show();
         }
        mView.undo();
        break;
   case R.id.Redo:
        mView.redo();
        break;

    default:
        break;
    }
}

public class MyView extends View {

        private float posX = 105;  
        private float posY = 105;  
        Mode mode;
        private Bitmap  mBitmap;
        private Canvas  mCanvas;
        private Path    mPath;
        private Paint   mBitmapPaint;
        ArrayList<Path> paths = new ArrayList<Path>();
        ArrayList<Path> undonePaths = new ArrayList<Path>();
        BlurMaskFilter blurMaskFilter = new BlurMaskFilter(10, BlurMaskFilter.Blur.OUTER);
        int screenWidth;
        int screenHeight;

    /**
     */
    public MyView(Context c) 
    {
        super(c);
        mBitmap=BitmapFactory.decodeResource(getResources(), R.drawable.e);
        mBitmap = Bitmap.createBitmap(800, 800, Bitmap.Config.ARGB_8888);            
        mCanvas = new Canvas(mBitmap);
        mPath = new Path();
        mBitmapPaint = new Paint(Paint.DITHER_FLAG);
        mCanvas.drawColor(0xFFFFFFFF);
        paths.add(mPath);           
    }       

    public void redo() {
        // TODO Auto-generated method stub
        if (undonePaths.size()>0) 
        { 
            paths.add(undonePaths.remove(undonePaths.size()-1)); 
            invalidate();
        } 
        else 
        {

        }

    }

    public void undo() {
        // TODO Auto-generated method stub

        Toast.makeText(getApplicationContext(), "Hello", 1000).show();
        if (paths.size()>0) 
        { 
           undonePaths.add(paths.remove(paths.size()-1));
           mView.invalidate();
           Toast.makeText(getApplicationContext(), "Undo", 1000).show();
         }
        else
        {
            Toast.makeText(getApplicationContext(), "Not", 1000).show();
        }
    }

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

    /**
     */
    @Override protected void onDraw(Canvas canvas) 
    {           
        canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);     
        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);
            mCanvas.drawPath(mPath, mPaint);
            paths.add(mPath);
            mPath.reset();        
        }

    @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;
        }

    public void drawImage (int resourceId)
    {
        Bitmap _scratch = BitmapFactory.decodeResource(getResources(), resourceId);

        mCanvas.drawBitmap(_scratch, 0, 0, null);
    } 

} 

} 

Upvotes: 0

Views: 3790

Answers (4)

Atihska
Atihska

Reputation: 5126

@Android Help: I solved this problem in my code. The problem is that as the paths are being added in onTouch cases but color selection is getting messed up so associate color with an integer in a class and then use that class for color changes where ever you are referencing. Let me know if you have any doubt. I can post my code here if not clear to you with solved problem

Upvotes: 0

Kevin Rameshwaran
Kevin Rameshwaran

Reputation: 119

Change your code like this....

public MyView(Context context, Object object) 
{
super(context);
setFocusable(true);
setFocusableInTouchMode(true);

mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(0xFFFFFF00);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(3);
mCanvas = new Canvas();
mPath = new Path();

mBitmap = Bitmap.createBitmap(320, 480, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
selectedcolor=context.getResources().getColor(com.example.videoapp.R.color.red);
}

protected void onDraw(Canvas canvas) 
{
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
for (Path p : paths)
{
mPaint.setColor(colorsMap.get(p));
canvas.drawPath(p, mPaint);
}

        mPaint.setColor(selectedcolor);
        canvas.drawPath(mPath, mPaint);
 }

In ontouch event..

ACTION_DOWN:

undonePaths.clear();
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
    invalidate();

ACTION_MOVE:

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

ACTION_UP:

mPath.lineTo(mX, mY);
paths.add(mPath);
    colorsMap.put(mPath,selectedcolor);
    mPath = new Path();
    mPath.reset();
invalidate();

Dont put this paths.add(mPath) in context and oncreate also...

    public MyView(Context context, Object object) 
    {
     super(context);
    //  paths.add(mPath);   // Dont put this line...
     }

Undo and Redo....

    undo.setOnClickListener(new View.OnClickListener() 
    {
public void onClick(View v) 
    {
if(MyView.paths.size()> 0) 
    {
 MyView.undonePaths.add(MyView.paths.remove(MyView.paths.size() - 1));
      mview.invalidate();
}
}
    });

    redo.setOnClickListener(new View.OnClickListener() 
    {
public void onClick(View v) 
    {
  if (MyView.undonePaths.size()>0) 
    { 
       MyView.paths.add(MyView.undonePaths.remove(MyView.undonePaths.size()-1));
       mview.invalidate();
    }
}
});

I hope this code is really veryuseful to u.. all the best

Upvotes: 2

Kevin Rameshwaran
Kevin Rameshwaran

Reputation: 119

I try this code it was working perfectly.....

Here is my code...

// declare the variable colorsMap.     

private Map<Path, Integer> colorsMap = new HashMap<Path, Integer>();  

//declare the integer variable selectedcolor

public static int selectedcolor;

 // set the color for integer varible like this code below.....

 public MyView(Context context, Object object) 
 {
  super(context);
  mBitmap = Bitmap.createBitmap(320, 480, Bitmap.Config.ARGB_8888);
  mCanvas = new Canvas(mBitmap);
  selectedcolor1=context.getResources().getColor(com.example.videoapp.R.color.red);
 } 


// In ONtouchevent

case MotionEvent.ACTION_UP:
paths.add(mPath);
colorsMap.put(mPath,selectedColor); // store the color of mPath


// Before drawing a path, you need to set the paint color:

protected void onDraw(Canvas canvas) {
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
for (Path p : paths)
{
    mPaint.setColor(colorsMap.get(p));
    canvas.drawPath(p, mPaint);
}
mPaint.setColor(selectedColor);
canvas.drawPath(mPath, mPaint);
}

I hope it was very useful and helpful to u. if u want to threecolor means declare three integer variables and set this in ondraw().

ENJOY FRIENDS................

Upvotes: 0

Kevin Rameshwaran
Kevin Rameshwaran

Reputation: 119

Dont put

  paths.add(mPath); 

in oncreate and context, put

 paths.add(mPath); 

in mouse up.

Upvotes: 0

Related Questions