Custom Brush mit Undo / Redo-Operation in Android Canvas

Ich möchte eine Zeichenanwendung für die Zeichenfläche mit benutzerdefiniertem Pinsel & Rückgängig / Wiederherstellen implementieren. Zunächst funktioniert mein Code perfekt, ohne den benutzerdefinierten Pinsel zu verwenden (einschließlich der Undo / Redo-Operation). Nach dieser AntwortWie mache ich benutzerdefinierte Pinsel für Leinwand in Android? Ich habe einfache Bildspitzen für das Zeichnen von Bitmaps verwendet.

Nun das Problem sind,

Der Vorgang zum Rückgängigmachen und Wiederherstellen funktioniert nicht. Benutzerdefinierte Pinsel malen immer wieder, wenn Sie die Berührungspunkte verschieben.

Q: Wie mache ich den Undo / Redo-Vorgang?

Die benutzerdefinierten Pinselheizer sind nicht glatt, wie sie sollten. Im Moment sehen sie rau und künstlich aus.

Q. Wie macht man das Bild mit benutzerdefinierten Pinselstrichen glatt und natürlich?

Überprüfen Sie meinen Beispielcode hier,

public class DrawingView extends View {

    private Context ctx;

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

    private Map<Path, Float> brushMap = new HashMap<Path, Float>();
    private Map<Path, List<Vector2>> customBrushMap = new HashMap<Path, List<Vector2>>();

    private Bitmap mBitmapBrush;
    private Vector2 mBitmapBrushDimensions;
    private List<Vector2> mPositions = new ArrayList<Vector2>(100);
    private boolean isCustomBrush = false;

    private int selectedColor;
    private float brushSize, lastBrushSize;

    private float mX, mY;
    private static final float TOUCH_TOLERANCE = 4;

    private Path drawPath;
    private Paint drawPaint, canvasPaint;
    private int paintColor = 0xFF660000, paintAlpha = 255;
    private Canvas drawCanvas;
    private Bitmap canvasBitmap;

    private static final class Vector2 {
        public Vector2(float x, float y) {
            this.x = x;
            this.y = y;
        }

        public final float x;
        public final float y;
    }

    public DrawingView(Context context, AttributeSet attrs) {
        super(context, attrs);
        ctx = context;
        setupDrawing();
    }

    private void setupDrawing() {
        brushSize = getResources().getInteger(R.integer.small_size);
        lastBrushSize = brushSize;

        drawPath = new Path();
        drawPaint = new Paint();
        drawPaint.setColor(paintColor);
        drawPaint.setAntiAlias(true);
        drawPaint.setDither(true);
        drawPaint.setStrokeWidth(brushSize);
        drawPaint.setStyle(Paint.Style.STROKE);
        drawPaint.setStrokeJoin(Paint.Join.ROUND);
        drawPaint.setStrokeCap(Paint.Cap.ROUND);
        canvasPaint = new Paint(Paint.DITHER_FLAG);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        drawCanvas = new Canvas(canvasBitmap);
    }

    private void touch_start(float x, float y) {
        undonePaths.clear();
        drawPath.reset();
        drawPath.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) {
            drawPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
            mX = x;
            mY = y;
        }
        customBrushMap.put(drawPath, mPositions);
    }

    private void touch_up() {
        drawPath.lineTo(mX, mY);
        drawCanvas.drawPath(drawPath, drawPaint);
        paths.add(drawPath);
        brushMap.put(drawPath, brushSize);
        drawPath = new Path();
        drawPath.reset();
        invalidate();
    }

    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 onTouchEvent(MotionEvent event) {

        //detect user touch
        float x = event.getX();
        float y = event.getY();

        switch (event.getAction() & MotionEvent.ACTION_MASK) {

            case MotionEvent.ACTION_DOWN:
                touch_start(x, y);
                invalidate();
                break;

            case MotionEvent.ACTION_MOVE:
                touch_move(x, y);
                if (isCustomBrush) {
                mPositions.add(new Vector2(x - mBitmapBrushDimensions.x / 2, y - mBitmapBrushDimensions.y / 2));
                }
                touch_move(x, y);
                invalidate();
                break;

            case MotionEvent.ACTION_POINTER_DOWN:
                invalidate();
                break;

            case MotionEvent.ACTION_UP:
                touch_up();
                invalidate();
                break;
        }

        return true;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.save();
        for (Path p : paths) {

        drawPaint.setColor(colorsMap.get(p));
        drawPaint.setShader(shaderMap.get(p));
        drawPaint.setStrokeWidth(brushMap.get(p));
        drawPaint.setAlpha(opacityMap.get(p));

        if (isCustomBrush) {
            if (customBrushMap.get(p) != null) {
                for (Vector2 pos : customBrushMap.get(p)) {
                    Paint paint = new Paint();
                    ColorFilter filter = new PorterDuffColorFilter(selectedColor, PorterDuff.Mode.SRC_IN);
                    paint.setColorFilter(filter);
                    canvas.drawBitmap(mBitmapBrush, pos.x, pos.y, paint);
                }
            }
        } else {
            canvas.drawPath(p, drawPaint);
            drawPaint.setColor(selectedColor);
            drawPaint.setStrokeWidth(brushSize);
            canvas.drawPath(drawPath, drawPaint);
        }
    }
        canvas.restore();
    }

    public void setCustomBrush(Activity activity, String customBrush) {
        isCustomBrush = true;
        invalidate();
        int patternID = getResources().getIdentifier(customBrush, "drawable", "com.androidapp.drawingstutorial");
        mBitmapBrush = BitmapFactory.decodeResource(getResources(), patternID);
        mBitmapBrushDimensions = new Vector2(mBitmapBrush.getWidth(), mBitmapBrush.getHeight());
    }
}

Antworten auf die Frage(2)

Ihre Antwort auf die Frage