Android - custom button with shape drawables and a gradient programmatically Android - custom button with shape drawables and a gradient programmatically android android

Android - custom button with shape drawables and a gradient programmatically


1) Use alignment to draw text at the center in your DrawableView (should help with the text seems off center):

paint.setTextAlign(Align.CENTER); // <- should help you with centeringpaint.getTextBounds(text, 0, 1, r);int x = w / 2, y = (d - r.height()) / 2; // <- was updated too

2) To answer your question the reason for the bounty is to figure out why subclassing drawable does not work:

I suppose it's because you create DrawableView in MyDrawable and don't add it to any container which means you don't measure and layout it. So, it's probably zero height and width.

3) I would suggest you to use Button instead of custom views and drawables. You extend from Button and do additional drawings in the end of onDraw method, something like this:

public void onDraw(Canvas canvas) {    super.onDraw(canvas);    // your custom drawing over button}

Original Incorrect Answer

the reason for the bounty is to figure out why subclassing drawable does not work

Try to check if you need to call:

  • super.onDraw(canvas) in DrawableView.onDraw
  • super.draw(canvas) in MyDrawable.draw


use this code to make gradient button

Button your_button= findViewById(R.id.button);    GradientDrawable gd = new GradientDrawable(            GradientDrawable.Orientation.TOP_BOTTOM,            new int[] {0xFF616261,0xFF131313});    gd.setCornerRadius(0f);    your_button.setBackgroundDrawable(gd);


It is not a good idea to create Drawable depended on a View.As Eugen Pechanec suggested, make MyDrawable and DrawableView static.

You are using ShapeDrawables only in MyDrawable, so you can move it from DrawableView.

It can be something like this:

public static class MyDrawable extends Drawable {    private ShapeDrawable d0, d1, d2;    private int edge;    private int border;    public MyDrawable(int color1, int color2, int radius, int edge, int border) {        this.edge = edge;        this.border = border;        float[] outerRadii = new float[] {                radius, radius,                radius, radius,                radius, radius,                radius, radius        };        d0 = new ShapeDrawable(new RoundRectShape(outerRadii, null, null));        d0.getPaint().setColor(0xff000000);        d1 = new ShapeDrawable(new RoundRectShape(outerRadii, null, null));        d1.getPaint().setColor(color1);        d2 = new ShapeDrawable(new RoundRectShape(outerRadii, null, null));        d2.getPaint().setColor(color2);    }    public void setAlpha(int alpha) {        System.out.println("ignoring set alpha to: " + alpha);    }    public void setColorFilter(ColorFilter colorFilter) {        System.out.println("ignoring set color filter to: " + colorFilter);    }    public int getOpacity() {        return PixelFormat.OPAQUE;    }    public void draw(Canvas canvas) {        System.out.println(this + " is drawing.");        d0.draw(canvas);        System.out.println("d0 bounds: " + d0.getBounds());        d1.draw(canvas);        System.out.println("d1 bounds: " + d1.getBounds());        d2.draw(canvas);        System.out.println("d2 bounds: " + d2.getBounds());    }    @Override    public void setBounds(int left, int top, int right, int bottom) {        super.setBounds(left, top, right, bottom);        d0.setBounds(left, top, right, bottom);        d1.setBounds(left + edge, top + edge, right - edge, bottom - edge);        d2.setBounds(left + border / 2, top + border / 2,                right - border / 2, bottom - border / 2);    }}

You can consider to not use ShapeDrawable and draw the shapes by yourself:

public static class MyDrawable extends Drawable {    private int radius;    private int edge;    private int border;    private RectF bounds1 = new RectF();    private RectF bounds2 = new RectF();    private RectF bounds3 = new RectF();    private Paint paint1 = new Paint();    private Paint paint2 = new Paint();    private Paint paint3 = new Paint();    public MyDrawable(int color1, int color2, int radius, int edge, int border) {        this.radius = radius;        this.edge = edge;        this.border = border;        float[] outerRadii = new float[] {                radius, radius,                radius, radius,                radius, radius,                radius, radius        };        paint1.setColor(0xff000000);        paint2.setColor(color1);        paint3.setColor(color2);    }    public void setAlpha(int alpha) {        System.out.println("ignoring set alpha to: " + alpha);    }    public void setColorFilter(ColorFilter colorFilter) {        System.out.println("ignoring set color filter to: " + colorFilter);    }    public int getOpacity() {        return PixelFormat.OPAQUE;    }    public void draw(Canvas canvas) {        canvas.drawRoundRect(bounds1, radius, radius, paint1);        canvas.drawRoundRect(bounds2, radius, radius, paint2);        canvas.drawRoundRect(bounds3, radius, radius, paint3);    }    @Override    public void setBounds(int left, int top, int right, int bottom) {        super.setBounds(left, top, right, bottom);        bounds1.set(left, top, right, bottom);        bounds2.set(bounds1);        bounds2.inset(edge, edge);        bounds3.set(bounds1);        bounds3.inset(border / 2, border / 2);    }}

By the way, it is good to use StateListDrawable for a Button.
So you can use MyDrawable like this:

MyDrawable drawable = new MyDrawable(...);MyDrawable drawablePressed = new MyDrawable(...);MyDrawable drawableFocused = new MyDrawable(...);StateListDrawable stateDrawable = new StateListDrawable();stateDrawable.addState(new int[]{android.R.attr.state_pressed}, drawablePressed);stateDrawable.addState(new int[]{android.R.attr.state_focused}, drawableFocused);stateDrawable.addState(new int[]{}, drawable);Button button = (Button) findViewById(R.id.button);button.setBackground(stateDrawable);