【问题标题】:How to undo Path from Canvas android?如何从 Canvas android 撤消路径?
【发布时间】:2015-04-24 19:59:42
【问题描述】:

我正在尝试删除在画布上绘制的最后一条路径。到目前为止,我已经尝试在 ArrayList 中添加我的路径,但我没有找到任何方法可以轻松地从画布中删除路径。

public class PaintView extends View {

    private Bitmap mBitmap;
    private Canvas mCanvas;
    private Path mPath;
    private Paint mPaint;
    private static final int TOUCH_TOLERANCE_DP = 20;
    private static final int BACKGROUND = Color.TRANSPARENT;
    private List<Point> mPoints = new ArrayList<Point>();
    private int mLastPointIndex = 0;
    private int mTouchTolerance;
    private boolean isPathStarted = false;
    private boolean canCreatePoints = true;
    private Polygon poly;
    private Builder build;
    private ArrayList<Polygon> polyList;
    private ArrayList<Path> undoPath, redoPath;

    public PaintView(Context context) {
        super(context);
        mCanvas = new Canvas();
        mPath = new Path();
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setColor(Color.BLACK);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(12);
        mTouchTolerance = dp2px(TOUCH_TOLERANCE_DP);

        polyList = new ArrayList<Polygon>();
        undoPath = new ArrayList<Path>();
        redoPath = new ArrayList<Path>();
    }

    @Override
    protected void onSizeChanged(int width, int height, int oldWidth,
            int oldHeight) {
        super.onSizeChanged(width, height, oldWidth, oldHeight);
        clear();

    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawColor(BACKGROUND);
        canvas.drawBitmap(mBitmap, 0, 0, null);
        canvas.drawPath(mPath, mPaint);

        for(Path p : undoPath) {
            canvas.drawPath(p, mPaint);
        }

        for (Point point : mPoints) {
            canvas.drawPoint(point.x, point.y, mPaint);
        }

    }

下面是 onTouch 方法,当变量 canCreatePoints 为真时,我使用 Path 创建线。如果 canCreatePoints 为假,我检查 ArrayList&lt;Polygon&gt; 如果我的接触点在多边形内。

@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();

switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
    if(canCreatePoints == true)
    {
        create_point(x,y);

        if( mPoints.size() > 1 )
        {
            // start point
            Point p = mPoints.get(mLastPointIndex);
            mPath.moveTo(p.x, p.y);
            // end point
            p = mPoints.get(mLastPointIndex + 1);
            mPath.lineTo(p.x, p.y);
            mCanvas.drawPath(mPath, mPaint);

            undoPath.add(mPath);

            mPath.reset();
            // increment point index
            ++mLastPointIndex;
        }
    }

    if(canCreatePoints == false)
    {
        Points pp = new Points(Math.round(x), Math.round(y));
        boolean contains;

        for(Polygon tempPoly:polyList){
            contains = tempPoly.contains(pp);
            if(contains == true)
            {
                Log.i("TEST","Poligonul contine punctul");
                Toast.makeText(getContext(),"Test poly "+polyList.indexOf(tempPoly), 
                        Toast.LENGTH_SHORT).show();
            }
        }

        }
        invalidate();
        break;
    }
    return true;
}

private void create_point(float x, float y){
    Point p = new Point(Math.round(x),Math.round(y));
    mPoints.add(p);
}

下面我通过一个按钮的动作完成了我的多边形形式。我创建了一条从最后一点到第一点的路径并将其绘制在画布上。

public void finnishDraw(){
    if( mPoints.size() > 1 )
    {
        // start point
        Point p = mPoints.get(0);
        mPath.moveTo(p.x, p.y);
        // end point
        p = mPoints.get( mPoints.size() - 1);
        mPath.lineTo(p.x, p.y);
        mCanvas.drawPath(mPath, mPaint);
        mPath.reset();
        invalidate();

        int x[] = new int[mPoints.size()];
        int y[] = new int[mPoints.size()];

        build = new Builder();

        for(int i=0 ; i<mPoints.size() ; i++)
        {
            p = mPoints.get(i);
            x[i] = p.x;
            y[i] = p.y;

            build.addVertex(new Points(x[i],y[i]));

            Log.i("TEST","Adaug la builder punctele "+x[i]+" si "+y[i]);
        }

        poly = build.build();

        polyList.add(poly);
        mPoints.clear();
        mLastPointIndex = 0;

    }
}

到目前为止,我只找到了一个在画线之前使用备份位图的解决方案,但我不明白它是如何工作的。

【问题讨论】:

    标签: java android


    【解决方案1】:

    您无法撤消 Canvas 上的 drawPath。来自documentation

    通过画布,您的绘图实际上是在底层执行的 位图,放置在窗口中。

    正如您所说,您需要一个备份位图来保存当前位图的状态,然后再对其进行绘制,例如使用Memento pattern

    看看Fast undo/redo for bitmap editor when memory is limited?Fast undo facility for bitmap editor application(最后一个针对iPhone,但基本思路是一样的)

    另一种减少内存消耗的方法是保存您想要在画布上绘制的对象的状态并按需绘制它们(当您需要显示部分或全部结果时)。

    【讨论】:

      【解决方案2】:

      要删除最后一个路径,只需应用此函数:

      public void clearLast(){
      
          if(!paths.isEmpty()) {
              backgroundColor = DEFAULT_BG_COLOR;
              int size = paths.size();
              paths.remove(paths.get(size-1));
              normal();
              invalidate();
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2012-06-22
        • 2011-09-18
        • 2016-01-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-09-19
        • 1970-01-01
        • 2012-03-16
        相关资源
        最近更新 更多