androidandroid-viewandroid-fragmentactivityandroid-graphics

Add Button to Graphics Canvas


I was using the answer to this question: Drawing on Canvas and save image in order to create a canvas to draw an image on.

I am currently opening a FragmentActivity called DrawImage when a button is clicked. In this activity I want MyDrawView to be displayed along with a floating action button which will allow the user to save their drawing when clicked.

This is how I am currently displaying the canvas, which works, but I do not know how to add the button on top of it. Any ideas?

DrawImage

public class DrawImage extends FragmentActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        View drawImageCanvas = new MyDrawView(this.getApplicationContext());
        setContentView(drawImageCanvas);
    }
}

MyDrawView (Same as on the link)

public class MyDrawView extends View {

private Bitmap  mBitmap;
private Canvas  mCanvas;
private Path    mPath;
private Paint   mBitmapPaint;
private Paint   mPaint;

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

    mPath = new Path();
    mBitmapPaint = new Paint(Paint.DITHER_FLAG);

    mPaint = new Paint();
    mPaint.setAntiAlias(true);
    mPaint.setDither(true);
    mPaint.setColor(0xFF000000);
    mPaint.setStyle(Paint.Style.STROKE);
    mPaint.setStrokeJoin(Paint.Join.ROUND);
    mPaint.setStrokeCap(Paint.Cap.ROUND);
    mPaint.setStrokeWidth(3);
}

@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();

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

public void clear(){
    mBitmap.eraseColor(Color.TRANSPARENT);
    invalidate();
    System.gc();
}
}

Solution

  • You are setting contentView as MyDrawView view only, so there will not be any more views (Buttons) in the layout. It is impossible to add Buttons in such way.

    Solution is to move MyDrawView to xml file (fragment_draw_image.xml) and set content v

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <com.example.misah.test.MyDrawView
            android:id="@+id/myView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Save Drawing"/>
    
    </RelativeLayout>
    

    and then setContentView(R.layout.fragment_draw_image); In the layout you have your drawing view and button on top of it, and anything else you wish.

    Edited:

    Add this constructors also to the MyDrawView, and you can use it from xml:

    public MyDrawView(Context c) {
        super(c);
        init();
    }
    
    public MyDrawView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }
    
    public MyDrawView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }
    
    public MyDrawView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }
    

    And add all that you are doint in Constructor to init method (drawing etc)

    enter image description here