当用画笔和颜色绘制时,android绘图变得长腿

时间:2013-11-25 12:35:25

标签: java android android-canvas

这是我第一次使用Android中的Canvas类

我想要的是使用Path类在画布上绘制不同的颜色和画笔。我不想使用Bitmap,因为我需要对它应用适当的撤消重做功能。我正在做的只是在画布上绘制,但在onDraw函数中,我使用for循环绘制整个路径,但如果用户选择不同的颜色和画笔来绘制,则会出现此问题。然后我将把所有这些存储在特定的Paint列表中,我现在正在做同样的事情。还有另一种好办法吗?

我使用的代码是:

DrawView类

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<Paint> paints = new ArrayList<Paint>();
private ArrayList<Path> undonePaths = new ArrayList<Path>();
private Context context;
private int initialcolor = 0xff000000;
private StyleEnum styleEnum;
private Style mStyle;
private int strokeWidth = 6;
private int effect;

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

    setFocusable(true);
    setFocusableInTouchMode(true);      
    this.setOnTouchListener(this);
    mPaint = new Paint();

    // add paint strokes
    addPaintStrokes(mPaint);

    mCanvas = new Canvas();
    mPath = new Path();
    paths.add(mPath);

    paints.add(mPaint);

    rect = new Rect();

    mRectPaint = new Paint(Paint.DITHER_FLAG);
    mRectPaint.setColor(Color.WHITE);
    mRectPaint.setStyle(Paint.Style.FILL);

    mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());

}

这里我使用另一个类型为Paint的ArrayList来包含要在每个新创建的对象上维护的绘制相关项

@Override
protected void onDraw(Canvas canvas) {

    float cX = canvas.getWidth() / 2.0f;        
    float cY = canvas.getHeight() / (mScaleFactor * 10);

    canvas.save();

    canvas.translate(mPosX, mPosY);

    canvas.scale(mScaleFactor, mScaleFactor, cX, cY);

    RectF rec = new RectF(0, 0, canvas.getWidth(), canvas.getHeight());

    canvas.drawRect(rec, mRectPaint);


    if( paths.size() > 0 ){
        for(int i = 0 ; i < paths.size() ; i++){
            canvas.drawPath(paths.get(i), paints.get(i));
        }
    }

    rect = canvas.getClipBounds();
    canvas.restore();
}
private void touch_start(float x, float y) {
    mStyle.strokeStart(x, 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 >= 4 || dy >= 4) {
        mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
        mStyle.stroke(mCanvas, x, y);
        mX = x;
        mY = y;
    }
}

private void touch_up() {
    mPath.lineTo(mX, mY);       
    mCanvas.drawPath(mPath, mPaint);                   
    mPath = new Path();
    paths.add(mPath);
    mPaint = new Paint();
    addPaintStrokes(mPaint);
    paints.add(mPaint);

}
public void onClickUndo () { 

    if (paths.size()>0)  { 
        undonePaths.add(paths.remove(paths.size()-1));
        invalidate();
    }
}

public void onClickRedo (){

    if (undonePaths.size()>0) {             
        paths.add(undonePaths.remove(undonePaths.size()-1));            
        invalidate();       
    }
}

@Override
public boolean onTouch(View arg0, MotionEvent event) {

    mScaleDetector.onTouchEvent(event);

    if (isDrawingEnabled) {

        // Drawing Enable

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

        x = x / mScaleFactor + rect.left;
        y = y / mScaleFactor + rect.top;

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

    } else{

        // Dragging Enable

        final int action = event.getAction();

        switch (action & MotionEvent.ACTION_MASK) {

        case MotionEvent.ACTION_DOWN: {

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

            mLastTouchX = x;
            mLastTouchY = y;

            mActivePointerId = event.getPointerId(0);

            break;
        }

        case MotionEvent.ACTION_MOVE: {

            final int pointerIndex = event.findPointerIndex(mActivePointerId);
            final float x = event.getX(pointerIndex);
            final float y = event.getY(pointerIndex);

            // Only move if the ScaleGestureDetector isn't processing

            if (!mScaleDetector.isInProgress()) {

                final float dx = x - mLastTouchX;
                final float dy = y - mLastTouchY;

                mPosX += dx;
                mPosY += dy;

                invalidate();
            }

            mLastTouchX = x;
            mLastTouchY = y;

            break;
        }

        case MotionEvent.ACTION_UP: {
            mActivePointerId = INVALID_POINTER_ID;
            break;
        }

        case MotionEvent.ACTION_CANCEL: {
            mActivePointerId = INVALID_POINTER_ID;
            break;
        }

        case MotionEvent.ACTION_POINTER_UP: {

            final int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
            final int pointerId = event.getPointerId(pointerIndex);

            if (pointerId == mActivePointerId) {
                // This was our active pointer going up. Choose a new
                // active pointer and adjust accordingly.
                final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
                mLastTouchX = event.getX(newPointerIndex);
                mLastTouchY = event.getY(newPointerIndex);
                mActivePointerId = event.getPointerId(newPointerIndex);
            }
        }

        break;
        }
    }
    return true;
}

private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {

    @Override
    public boolean onScale(ScaleGestureDetector detector) {

        if(!isDrawingEnabled){

            mScaleFactor *= detector.getScaleFactor();

            // Don't let the object get too small or too large.
            mScaleFactor = Math.max(1.0f, Math.min(mScaleFactor, 5.0f));

            invalidate();
        }

        return true;

    }
}
private void addPaintStrokes(Paint p){

    p.setAntiAlias(true);
    p.setDither(true);
    p.setColor(initialcolor);

    setBrushStyle(effect);

    p.setStyle(Paint.Style.STROKE);
    p.setStrokeJoin(Paint.Join.ROUND);
    p.setStrokeCap(Paint.Cap.ROUND);
    p.setStrokeWidth(getStrokeWidth());
}
public void setBrushStyle(int mBrushStyle) {

    Log.e("mBrushStyle : ", "" + mBrushStyle);

    this.effect = mBrushStyle;

    switch (mBrushStyle) {
        case 0: {
            mPaint.setMaskFilter(null);
            break;
        }
        case 1: {
            MaskFilter mEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 },
                    0.4f, 6, 3.5f);
            mPaint.setMaskFilter(mEmboss);
            break;
        }
        case 2: {
            int brushSize = getStrokeWidth();

            if (brushSize > 0) {
                MaskFilter mBlur = new BlurMaskFilter(brushSize,
                        BlurMaskFilter.Blur.NORMAL);
                mPaint.setMaskFilter(mBlur);
            } else {
                MaskFilter mBlur = new BlurMaskFilter(1,
                        BlurMaskFilter.Blur.NORMAL);
                mPaint.setMaskFilter(mBlur);
            }
            break;
        }
    }
}

2 个答案:

答案 0 :(得分:1)

尝试将路径移动到undonePaths以在删除路径时保存路径。

撤消逻辑: 1.将当前路径移动到undonePaths(temp arraylist) 2.删除路径arraylist的当前路径。

重做逻辑: 1.将当前的undonePaths添加到路径arraylist 2.从undonePaths中删除移动的路径

这对我来说是gd,请尝试下面的代码段。

public void onClickUndo() {
    if (paths.size() > 0) {
        undonePaths.add(paths.remove(paths.size() - 1));
        invalidate();
    } else {

    }

}

public void onClickRedo() {
    if (undonePaths.size() > 0) {
        paths.add(undonePaths.remove(undonePaths.size() - 1));
        invalidate();
    } else {

    }

}

享受编码:) :):)

答案 1 :(得分:0)

问题在于,添加了每个路径后,每次调用onDraw时,您都会在屏幕上累积更多内容。

如果您可以限制允许的撤消数量,则可以使用位图执行此操作。像这样创建你的位图:

    @Override
    protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
        super.onSizeChanged(width, h, oldWidth, oldHeight);
        mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mBitmap);
    }

touch_up方法中,一旦paths ArrayList达到一定大小(您将支持的撤消级别数),请取其第一个路径并将其绘制到mCanvas (在此方法中,因此只执行一次)并将其从ArrayList(以及与其他ArrayList关联的Paint)中删除。在onDraw方法中,首先绘制位图。

如果你必须有无限制的撤销,我认为你仍然可以用Bitmap做到这一点。只需保留您现在拥有的相同数组列表,但只能在触摸方法中绘制到mBitmap。仅在mBitmap方法中绘制onDraw。当您需要撤消时,您可以清除mBitmap,删除最后一条路径,并将所有剩余路径重绘为mBitmap一次。