Search code examples
androidandroid-edittextandroid-viewandroid-custom-view

Overwriting onDraw on EditText


I'm writing a subclass of EditText that allows the user to draw with his finger on it. For that, I created a boolean called drawing, that if it's true put the EditText on drawing mode and the keyboard it's not opened, and if it's false allow the user to open the keyboard and write on keeping his drawing that he does with the drawing mode.

The code for the drawing is based on the Google Android Example called FingerPaint. Before this intent to implement this into an EditText, the code was implemented on a subclass of view, and worked perfectly, but the problem was that combining an EditText and that view in a layout reduces the performance was really bad.

There's a lot of code to do this, because can be used to implement two different mask filters that add some lines to this code that are not used locally in this class.

My problem is that when I override the onDraw(), and drawing is false, the texts it's not showed to ther user, but the keyboard and the writing line (|) are showed.

Here my code:

import android.content.Context;
import android.graphics.*;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.EditText;

public class DrawEditText extends EditText {

    private Bitmap  mBitmap;
    private Canvas  mCanvas;
    private Path    mPath;
    private Paint   mBitmapPaint;
    private Paint   mPaint;
    private MaskFilter  mEmboss;
    private MaskFilter  mBlur;

    private Boolean drawing;

    public DrawEditText(Context c) {
        super(c);


        //This initializes all the objects
        mPath = new Path();
        mBitmapPaint = new Paint(Paint.DITHER_FLAG);

        mPaint = new Paint();
        mPaint.setColor(Color.BLACK);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(5);
        mPaint.setAntiAlias(true);

        mEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 },
                0.4f, 6, 3.5f);

        mBlur = new BlurMaskFilter(8, BlurMaskFilter.Blur.NORMAL);

        drawing = true;
    }
    public DrawEditText(Context c, AttributeSet attrs) {
        super(c, attrs);

        //This initializes all the objects
        mPath = new Path();
        mBitmapPaint = new Paint(Paint.DITHER_FLAG);

        mPaint = new Paint();
        mPaint.setColor(Color.BLACK);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(5);
        mPaint.setAntiAlias(true);

        mEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 },
                0.4f, 6, 3.5f);

        mBlur = new BlurMaskFilter(8, BlurMaskFilter.Blur.NORMAL);

        drawing = true;
    }

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

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
        canvas.drawPath(mPath, 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);
        // commit the path to our offscreen
        mCanvas.drawPath(mPath, mPaint);
        // kill this so we don't double draw
        mPath.reset();
    }

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

        //This conditional makes that if not it's drawing no points are saved and no points are drawed
        if (drawing){
            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;
        } else {
            return super.onTouchEvent(event);
        }
    }

    public void changePaint(int stroke, int color){
        mPaint.setColor(color);
        mPaint.setStrokeWidth(stroke);
    }
    public void clear(){
        mCanvas.drawColor(0x00AAAAAA);
        mCanvas.drawColor( 0, PorterDuff.Mode.CLEAR );
    }
    public void changeBrush(int id){
        //String[] ids={"emboss", "blur", "another"};
        switch (id) {
        case 0:
            mPaint.setMaskFilter(mEmboss);
            break;
        case 1:
            mPaint.setMaskFilter(mBlur);                
            break;
        case 2:
            mPaint.setMaskFilter(null);         
            break;
        default:
            mPaint.setMaskFilter(null);
            break;
        }
    }
    public void eraser(){
        mPaint.setMaskFilter(null); 
        mPaint.setColor(0x00AAAAAA);
    }

    public void setDrawing(Boolean drawing){
        this.drawing = drawing;
    }

    public Boolean isDrawing(){
        return drawing;
    }
}

Solution

  • Just give the EditText a chance to draw its own content:

    @Override
    protected void onDraw(Canvas canvas) {
        if(drawing) {
          canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
          canvas.drawPath(mPath, mPaint);
        } else {
          super.onDraw(canvas);
        }
    }