我的Andr​​oid如何实现撤销/重做上SurfaceView [英] Android How Can I Implement Undo/Redo on SurfaceView

查看:189
本文介绍了我的Andr​​oid如何实现撤销/重做上SurfaceView的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用SurfaceView对位图绘制。我想实现它撤消重做功能。我与节能接触点这样做。

我收到的用户得出触摸点和接触点的ArrayList保存在它3恒定的标志来定义触摸启动器,触摸移动和润色。当用户进行撤销,我从接触点ArrayList和店undotouchpoints ArrayList中的最后一个画点和接触点ArrayList中删除,然后失效()在屏幕上进行操作,当用户执行重做,我从undotouchpoints名单获得接触点,并添加在接触点ArrayList中,从undotouchpoints删除的ArrayList然后验证()在屏幕上进行操作。

我面临的问题是,当撤消触发器,如果​​划线上,我要执行撤消,是在最多另一行的,那么这两个行的,其中它们碰撞coordiantes(X,Y)都删除从屏幕。请指引我。

DrawView类

 公共类DrawView扩展SurfaceView实现SurfaceHolder.Callback {公共DrawView(上下文C,ATTRS的AttributeSet){
    超(C,ATTRS);
    this.c = C;    mHolder = getHolder();
    mHolder.addCallback(本);
}
公众的ArrayList< TouchInfo> getRedo(){    INT firstIndex = 0;
    INT lastIndex的= undoTouchPoints.size() - 1;
    ArrayList的< TouchInfo>临时=新的ArrayList< TouchInfo>();    如果(undoTouchPoints.size()大于0){        的for(int i = lastIndex的; I> 0;我 - ){            如果(undoTouchPoints.get(ⅰ).getAction()== Action.TOUCH_START){
                firstIndex = I;
                打破;
            }
        }        Log.i(DrawView,尺寸:+ undoTouchPoints.size());
        Log.i(DrawView,FirstIndex:+ firstIndex);
        Log.i(DrawView,lastIndex的:+ lastIndex的);        对于(INT I = firstIndex; I< = lastIndex的;我++){            drawnTouchpoints.add(新TouchInfo(
                            undoTouchPoints.get(ⅰ).getPoint()。X,
                            undoTouchPoints.get(我).getPoint()。Y,
                            undoTouchPoints.get(ⅰ).getAction(),
                            undoTouchPoints.get(ⅰ).getColor(),
                            undoTouchPoints.get(ⅰ).getStrokeWidth(),
                            undoTouchPoints.get(ⅰ).getStyle()));            temp.add(新TouchInfo(undoTouchPoints.get(ⅰ)));
        }        //undoTouchPoints.subList(firstIndex,lastIndex的).clear();
        undoTouchPoints.clear();
    }    返回温度;
}
公众的ArrayList< TouchInfo> getUndo(){    INT firstIndex = 0;
    INT lastIndex的= drawnTouchpoints.size() - 1;
    ArrayList的< TouchInfo>临时=新的ArrayList< TouchInfo>();    如果(drawnTouchpoints.size()大于0&放大器;&放大器; undoTouchPoints.isEmpty()){        的for(int i = lastIndex的; I> = 0;我 - ){            如果(drawnTouchpoints.get(ⅰ).getAction()== Action.TOUCH_START){
                firstIndex = I;
                打破;
            }
        }        对于(INT I = firstIndex; I< = lastIndex的;我++){
            undoTouchPoints.add(新TouchInfo(drawnTouchpoints.get(ⅰ)));
            temp.add(新TouchInfo(drawnTouchpoints.get(ⅰ)));
        }        drawnTouchpoints.subList(firstIndex和lastIndex的).clear();    }    返回温度;
}
@覆盖
保护无效的onDraw(帆布油画){    canvas.drawPath(的mpath,mBitmapPaint);}
公共无效drawAuto(){    如果(计数器< touchPoints.size()){
        TouchInfo TI = touchPoints.get(计数器++);
        //Log.i(\"ti,ti.toString());        如果(ti.getAction()== Action.TOUCH_START){            // mStyle = NewStylesFactory.getStyleInstance(ti.getStyle());            //Log.i(\"mStyle空?,+(mStyle == NULL));
            mStyle.setPaint(mPaint);            touch_start(ti.getPoint()X,ti.getPoint()Y。);
            mPaint.setColor(ti.getColor());
            mPaint.setStrokeWidth(ti.getStrokeWidth());
            setBrushStyle(ti.getEffect());
            //无效();
        }否则如果(ti.getAction()== Action.TOUCH_MOVE){            mStyle.setPaint(mPaint);
            TOUCH_MOVE(ti.getPoint()X,ti.getPoint()Y。);
            mPaint.setColor(ti.getColor());
            mPaint.setStrokeWidth(ti.getStrokeWidth());
            setBrushStyle(ti.getEffect());
            //无效();
        }否则如果(ti.getAction()== Action.TOUCH_UP){
            mStyle.setPaint(mPaint);
            润色();
            mPaint.setColor(ti.getColor());
            mPaint.setStrokeWidth(ti.getStrokeWidth());
            setBrushStyle(ti.getEffect());            //无效();
        }否则如果(ti.getAction()== Action.ERASE){
            this.autoErase();
        }        ((活动)C).runOnUiThread(新的Runnable(){            @覆盖
            公共无效的run(){
                //无效();
                mCanvas.drawPath(的mpath,mBitmapPaint);
                画();
            }
        });        ((活动)C).runOnUiThread(新的Runnable(){            @覆盖
            公共无效的run(){
                无效();
            }
        });
    }
}
公共无效drawAuto(INT颜色){    如果(计数器< touchPoints.size()){
        TouchInfo TI = touchPoints.get(计数器++);
        Log.i(钛,ti.toString());        如果(ti.getAction()== Action.TOUCH_START){            // mStyle = NewStylesFactory.getStyleInstance(ti.getStyle());            Log.i(mStyle空?,+(mStyle == NULL));
            mStyle.setPaint(mPaint);
            touch_start(ti.getPoint()X,ti.getPoint()Y。);
            mPaint.setColor(颜色);
            mPaint.setStrokeWidth(ti.getStrokeWidth()+ 5);
            setBrushStyle(ti.getEffect());
            //无效();
        }否则如果(ti.getAction()== Action.TOUCH_MOVE){            mStyle.setPaint(mPaint);
            TOUCH_MOVE(ti.getPoint()X,ti.getPoint()Y。);
            mPaint.setColor(颜色);
            mPaint.setStrokeWidth(ti.getStrokeWidth()+ 5);
            setBrushStyle(ti.getEffect());
            //无效();
        }否则如果(ti.getAction()== Action.TOUCH_UP){
            mStyle.setPaint(mPaint);
            润色();
            mPaint.setColor(颜色);
            mPaint.setStrokeWidth(ti.getStrokeWidth()+ 5);
            setBrushStyle(ti.getEffect());            //无效();
        }否则如果(ti.getAction()== Action.ERASE){
            this.autoErase();
        }        ((活动)C).runOnUiThread(新的Runnable(){            @覆盖
            公共无效的run(){
                //无效();
                mCanvas.drawPath(的mpath,mBitmapPaint);
                画();
            }
        });
    }
}
私人无效touch_start(浮法X,浮法Y){mStyle.strokeStart(X,Y​​);
mPath.reset();
mPath.moveTo(X,Y);}
私人无效TOUCH_MOVE(浮法X,浮法Y){    mStyle.stroke(mCanvas,X,Y);
}私人无效touch_up(){
    // mPath.lineTo(MX,我的);
    //提交的路径,我们的屏幕外
    // mCanvas.drawPath(的mpath,mPaint);
    //杀死这个,所以我们不要双击平局
    // mPath.moveTo(MX,我的);
    // mPath.reset();}
@覆盖
公共布尔onTouchEvent(MotionEvent事件){    浮X = event.getX();
    浮Y = event.getY();    开关(event.getAction()){        案例MotionEvent.ACTION_DOWN:            //明确撤消接触点列表中删除所有previous X,Y点
            undoTouchPoints.clear();            touch_start(X,Y​​);            drawnTouchpoints.add(新TouchInfo((INT)X,(INT)Y,
                    Action.TOUCH_START,mPaint.getColor(),mPaint
                    .getStrokeWidth(),styleEnum.ordinal(),
                    影响));            redoTouchPoints.add(新TouchInfo((INT)X,(INT)Y,
                    Action.TOUCH_START,mPaint.getColor(),mPaint
                    .getStrokeWidth(),styleEnum.ordinal(),
                    影响));
            mCanvas.drawPath(的mpath,mBitmapPaint);
            画();            打破;        案例MotionEvent.ACTION_MOVE:            TOUCH_MOVE(X,Y);            drawnTouchpoints.add(新TouchInfo((INT)X,(INT)Y,
                    Action.TOUCH_MOVE,mPaint.getColor(),mPaint
                    .getStrokeWidth(),styleEnum.ordinal(),
                    影响));            redoTouchPoints.add(新TouchInfo((INT)X,(INT)Y,
                    Action.TOUCH_MOVE,mPaint.getColor(),mPaint
                    .getStrokeWidth(),styleEnum.ordinal(),
                    影响));            mCanvas.drawPath(的mpath,mBitmapPaint);
            画();
            打破;        案例MotionEvent.ACTION_UP:            润色();            drawnTouchpoints.add(新TouchInfo((INT)X,(INT)Y,
                    Action.TOUCH_UP,mPaint.getColor(),mPaint
                    .getStrokeWidth(),styleEnum.ordinal(),
                    影响));            redoTouchPoints.add(新TouchInfo((INT)X,(INT)Y,
                    Action.TOUCH_UP,mPaint.getColor(),mPaint
                    .getStrokeWidth(),styleEnum.ordinal(),
                    影响));            mCanvas.drawPath(的mpath,mBitmapPaint);
            画();
            打破;
    }    无效();    返回true;}
@覆盖
公共无效surfaceCreated(SurfaceHolder持有人){    宽度=的getWidth();
    高度=的getHeight();
    mCanvas =新的Canvas();
    mBitmap = Bitmap.createBitmap(宽度,高度,Bitmap.Config.ARGB_8888); //后台缓冲区
    mCanvas.setBitmap(mBitmap);
    mCanvas.drawColor(Color.WHITE);    mBitmapPaint =新的油漆();
    mBitmapPaint.setColor(Color.RED);
    mBitmapPaint.setStrokeWidth(10);
    mBitmapPaint.setStrokeCap​​(Paint.Cap.ROUND);
    mBitmapPaint.setStrokeJoin(Paint.Join.ROUND);
    mBitmapPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
    mBitmapPaint.setFlags(Paint.DITHER_FLAG);
    mBitmapPaint.setAntiAlias​​(真);
    mBitmapPaint.setDither(真);    款式风格= NewStylesFactory.getStyleInstance(14);
    style.setPaint(mBitmapPaint);    // EXTRAS START
    的mpath =新路径();
    paths.add(的mpath);    mCanvas.setDrawFilter(新PaintFlagsDrawFilter(Paint.ANTI_ALIAS_FLAG,Pa​​int.DITHER_FLAG));
    画();
}
保护无效平局()
{
    帆布帆布= NULL;
    尝试{
        帆布= mHolder.lockCanvas(NULL);        canvas.drawBitmap(mBitmap,0,0,mBitmapPaint);
    }赶上(例外前){
        ex.printStackTrace();
    }最后{
        如果(mHolder!= NULL)mHolder.unlockCanvasAndPost(画布);
    }
}

绘画活动

 公共类DrawingActivity扩展活动实现回调{undoButton.setOnClickListener(新OnClickListener(){        @覆盖
        公共无效的onClick(视图v){
            // TODO自动生成方法存根
            drawView.onClickUndo();
}
});redoButton.setOnClickListener(新OnClickListener(){        @覆盖
        公共无效的onClick(视图v){
            // TODO自动生成方法存根
            drawView.onClickRedo();
}
});


解决方案

一般来说,我们应该清除画布(如你创建你自己)在画布上重绘之前,
除非你想覆盖。
当撤消可以清除画布就像你在做surfaceCreated()方法:

  mCanvas.drawColor(Color.WHITE); //清除与白色画布

然后重绘所有的事情上mCanvas。

顺便说一句,这是很好的使用命令模式来实现撤销/重做动作。

I am using SurfaceView for drawing on Bitmap. I want to implement Undo Redo feature on it. I am doing this with saving Touch Points.

I am getting users draw touch points and saving in touchpoints ArrayList with 3 constant flags in it to define where Touch START, Touch MOVE and Touch UP. When user perform Undo, I get the last draw points from touchpoints ArrayList and store in undotouchpoints ArrayList and remove from touchpoints ArrayList and then invalidate() to perform action on screen , when user perform Redo, i get the touch points from undotouchpoints list and add in touchpoints ArrayList, remove from undotouchpoints ArrayList then invalidate() to perform action on screen.

Problem I am facing is that, when undo trigger and if drawn line on which i going to perform undo, is on up of another line, then the coordiantes (x,y) of both the lines where they collide are both remove from screen. Please guide me.

DrawView class

public class DrawView extends SurfaceView implements SurfaceHolder.Callback{

public DrawView(Context c, AttributeSet attrs) {
    super(c, attrs);
    this.c = c;

    mHolder = getHolder();
    mHolder.addCallback(this);
}
public ArrayList<TouchInfo> getRedo() {

    int firstIndex = 0;
    int lastIndex = undoTouchPoints.size() - 1;
    ArrayList<TouchInfo> temp = new ArrayList<TouchInfo>();

    if ( undoTouchPoints.size() > 0 ) {

        for (int i = lastIndex; i > 0; i--) {

            if (undoTouchPoints.get(i).getAction() == Action.TOUCH_START) {
                firstIndex = i;
                break;
            }
        }

        Log.i("DrawView", "Size: " + undoTouchPoints.size());
        Log.i("DrawView", "FirstIndex: " + firstIndex);
        Log.i("DrawView", "LastIndex: " + lastIndex);

        for (int i = firstIndex; i <= lastIndex; i++) {

            drawnTouchpoints.add(new TouchInfo(
                            undoTouchPoints.get(i).getPoint().x,
                            undoTouchPoints.get(i).getPoint().y,
                            undoTouchPoints.get(i).getAction(),
                            undoTouchPoints.get(i).getColor(),
                            undoTouchPoints.get(i).getStrokeWidth(),
                            undoTouchPoints.get(i).getStyle()));

            temp.add(new TouchInfo(undoTouchPoints.get(i)));
        }

        //undoTouchPoints.subList(firstIndex, lastIndex).clear();
        undoTouchPoints.clear();
    }

    return temp;
}
public ArrayList<TouchInfo> getUndo() {

    int firstIndex = 0;
    int lastIndex = drawnTouchpoints.size() - 1;
    ArrayList<TouchInfo> temp = new ArrayList<TouchInfo>();

    if ( drawnTouchpoints.size() > 0 && undoTouchPoints.isEmpty() ) {

        for (int i = lastIndex; i >= 0; i--) {

            if (drawnTouchpoints.get(i).getAction() == Action.TOUCH_START) {
                firstIndex = i;
                break;
            }
        }

        for (int i = firstIndex; i <= lastIndex; i++) {
            undoTouchPoints.add(new TouchInfo(drawnTouchpoints.get(i)));
            temp.add(new TouchInfo(drawnTouchpoints.get(i)));
        }

        drawnTouchpoints.subList(firstIndex, lastIndex).clear();

    }

    return temp;
}
@Override
protected void onDraw(Canvas canvas) {

    canvas.drawPath(mPath, mBitmapPaint);

}
public void drawAuto() {

    if (counter < touchPoints.size()) {
        TouchInfo ti = touchPoints.get(counter++);
        //Log.i("ti", ti.toString());

        if (ti.getAction() == Action.TOUCH_START) {

            // mStyle = NewStylesFactory.getStyleInstance(ti.getStyle());

            //Log.i("mStyle null???", "" + (mStyle == null));
            mStyle.setPaint(mPaint);

            touch_start(ti.getPoint().x, ti.getPoint().y);
            mPaint.setColor(ti.getColor());
            mPaint.setStrokeWidth(ti.getStrokeWidth());
            setBrushStyle(ti.getEffect());
            // invalidate();
        } else if (ti.getAction() == Action.TOUCH_MOVE) {

            mStyle.setPaint(mPaint);
            touch_move(ti.getPoint().x, ti.getPoint().y);
            mPaint.setColor(ti.getColor());
            mPaint.setStrokeWidth(ti.getStrokeWidth());
            setBrushStyle(ti.getEffect());
            // invalidate();
        } else if (ti.getAction() == Action.TOUCH_UP) {
            mStyle.setPaint(mPaint);
            touch_up();
            mPaint.setColor(ti.getColor());
            mPaint.setStrokeWidth(ti.getStrokeWidth());
            setBrushStyle(ti.getEffect());

            // invalidate();
        } else if (ti.getAction() == Action.ERASE) {
            this.autoErase();
        }

        ((Activity) c).runOnUiThread(new Runnable() {

            @Override
            public void run() {
                //invalidate();
                mCanvas.drawPath(mPath, mBitmapPaint);
                draw();
            }
        });

        ((Activity) c).runOnUiThread(new Runnable() {

            @Override
            public void run() {
                invalidate();
            }
        });
    }
}
public void drawAuto(int color) {

    if (counter < touchPoints.size()) {
        TouchInfo ti = touchPoints.get(counter++);
        Log.i("ti", ti.toString());

        if (ti.getAction() == Action.TOUCH_START) {

            // mStyle = NewStylesFactory.getStyleInstance(ti.getStyle());

            Log.i("mStyle null???", "" + (mStyle == null));
            mStyle.setPaint(mPaint);
            touch_start(ti.getPoint().x, ti.getPoint().y);
            mPaint.setColor(color);
            mPaint.setStrokeWidth(ti.getStrokeWidth() + 5);
            setBrushStyle(ti.getEffect());
            // invalidate();
        } else if (ti.getAction() == Action.TOUCH_MOVE) {

            mStyle.setPaint(mPaint);
            touch_move(ti.getPoint().x, ti.getPoint().y);
            mPaint.setColor(color);
            mPaint.setStrokeWidth(ti.getStrokeWidth() + 5);
            setBrushStyle(ti.getEffect());
            // invalidate();
        } else if (ti.getAction() == Action.TOUCH_UP) {
            mStyle.setPaint(mPaint);
            touch_up();
            mPaint.setColor(color);
            mPaint.setStrokeWidth(ti.getStrokeWidth() + 5);
            setBrushStyle(ti.getEffect());

            // invalidate();
        } else if (ti.getAction() == Action.ERASE) {
            this.autoErase();
        }

        ((Activity) c).runOnUiThread(new Runnable() {

            @Override
            public void run() {
                //invalidate();
                mCanvas.drawPath(mPath, mBitmapPaint);
                draw();
            }
        });
    }
}
private void touch_start(float x, float y) {

mStyle.strokeStart(x, y);
mPath.reset();
mPath.moveTo(x, y);

}
private void touch_move(float x, float y) {     

    mStyle.stroke(mCanvas, x, 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.moveTo(mX, mY);
    // mPath.reset();       

}
@Override
public boolean onTouchEvent(MotionEvent event) {

    float x = event.getX();
    float y = event.getY();

    switch (event.getAction()) {

        case MotionEvent.ACTION_DOWN:

            // clear undo Touch-Points list to remove all previous x,y points
            undoTouchPoints.clear();

            touch_start(x, y);

            drawnTouchpoints.add(new TouchInfo((int) x, (int) y,
                    Action.TOUCH_START, mPaint.getColor(), mPaint
                    .getStrokeWidth(), styleEnum.ordinal(),
                    effect));

            redoTouchPoints.add(new TouchInfo((int) x, (int) y,
                    Action.TOUCH_START, mPaint.getColor(), mPaint
                    .getStrokeWidth(), styleEnum.ordinal(),
                    effect));
            mCanvas.drawPath(mPath, mBitmapPaint);
            draw();

            break;

        case MotionEvent.ACTION_MOVE:

            touch_move(x, y);

            drawnTouchpoints.add(new TouchInfo((int) x, (int) y,
                    Action.TOUCH_MOVE, mPaint.getColor(), mPaint
                    .getStrokeWidth(), styleEnum.ordinal(),
                    effect));

            redoTouchPoints.add(new TouchInfo((int) x, (int) y,
                    Action.TOUCH_MOVE, mPaint.getColor(), mPaint
                    .getStrokeWidth(), styleEnum.ordinal(),
                    effect));

            mCanvas.drawPath(mPath, mBitmapPaint);
            draw();
            break;

        case MotionEvent.ACTION_UP:

            touch_up();

            drawnTouchpoints.add(new TouchInfo((int) x, (int) y,
                    Action.TOUCH_UP, mPaint.getColor(), mPaint
                    .getStrokeWidth(), styleEnum.ordinal(),
                    effect));

            redoTouchPoints.add(new TouchInfo((int) x, (int) y,
                    Action.TOUCH_UP, mPaint.getColor(), mPaint
                    .getStrokeWidth(), styleEnum.ordinal(),
                    effect));

            mCanvas.drawPath(mPath, mBitmapPaint);
            draw();
            break;
    }

    invalidate();

    return true;

}
@Override
public void surfaceCreated(SurfaceHolder holder) {

    width = getWidth();
    height = getHeight();
    mCanvas = new Canvas();
    mBitmap = Bitmap.createBitmap( width, height, Bitmap.Config.ARGB_8888); // back buffer
    mCanvas.setBitmap(mBitmap);
    mCanvas.drawColor(Color.WHITE);

    mBitmapPaint = new Paint();
    mBitmapPaint.setColor(Color.RED);
    mBitmapPaint.setStrokeWidth(10);
    mBitmapPaint.setStrokeCap(Paint.Cap.ROUND);
    mBitmapPaint.setStrokeJoin(Paint.Join.ROUND);
    mBitmapPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
    mBitmapPaint.setFlags(Paint.DITHER_FLAG);
    mBitmapPaint.setAntiAlias(true);
    mBitmapPaint.setDither(true);

    Style style = NewStylesFactory.getStyleInstance(14);
    style.setPaint(mBitmapPaint);

    //EXTRAS START
    mPath = new Path();


    paths.add(mPath);

    mCanvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.ANTI_ALIAS_FLAG,Paint.DITHER_FLAG));
    draw();
}
protected void draw() 
{
    Canvas canvas = null;
    try{
        canvas = mHolder.lockCanvas(null);

        canvas.drawBitmap(mBitmap, 0,0, mBitmapPaint);


    }catch(Exception ex){
        ex.printStackTrace();
    }finally{
        if(mHolder!=null)  mHolder.unlockCanvasAndPost(canvas);
    }
}

Drawing Activity

public class DrawingActivity extends Activity implements Callback {

undoButton.setOnClickListener(new OnClickListener() {

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


            drawView.onClickUndo();
}
});

redoButton.setOnClickListener(new OnClickListener() {

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


            drawView.onClickRedo();
}
});

解决方案

Generally we should clear the canvas(as you create it yourself) before redraw on the canvas, unless you do want the overlay. When Undo you can clear the canvas like you did in surfaceCreated() method:

mCanvas.drawColor(Color.WHITE); // clear the canvas with white color

and then redraw all the things on mCanvas.

BTW, it is good to use Command Pattern to implement Undo/Redo action.

这篇关于我的Andr​​oid如何实现撤销/重做上SurfaceView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆