title: Android - custom button with shape drawables and a gradient programmatically
body: <p>I want to make a custom button like this program does with perhaps a radial gradient. </p>
  
  <p>I subclassed view, and draw three shape drawables and then draw the text. the text seems off center, so I tried to draw a bounding rectangle for the text, but no luck there. and was planning on adding a click listener to get button like behaviour.</p>
  
  <p>perhaps I should subclass button, but where to draw my drawables so they don't get messed up by the button's text being drawn.</p>
  
  <p>Any pointers will be appreciated.</p>
  
  <p>thanks</p>
  
  <p>Edit2: see second attempt below.</p>
  
  <p>Edit3: the reason for the bounty is to figure out why subclassing drawable does not work. the gradient is not so important.</p>
  
  <p>edit4: discovered drawRect before getTextBounds() in DrawableView::OnDraw().</p>
  
  <pre><code>package acme.drawables;
  import android.content.*;
  import android.content.pm.*;
  import android.graphics.*;
  import android.graphics.drawable.*;
  import android.graphics.drawable.shapes.*;
  import android.support.v7.app.AppCompatActivity;
  import android.os.Bundle;
  import android.util.*;
  import android.view.Menu;
  import android.view.View;
  import android.widget.*;
  import static java.lang.Math.*;
  public class MainActivity extends AppCompatActivity {
      DrawableView drawableView;
      LinearLayout row(boolean isRow1) {
          LinearLayout layout=new LinearLayout(this);
          layout.setOrientation(LinearLayout.HORIZONTAL);
          LinearLayout.LayoutParams layoutParams=new LinearLayout.LayoutParams(w,d);
          int m=(int)round(w*margin);
          layoutParams.setMargins(m,m,m,m);
          for(int i=0;i&lt;n;i++)
              layout.addView(drawableView=new DrawableView(this,i,isRow1),layoutParams);
          return layout;
      }
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
          DisplayMetrics metrics=new DisplayMetrics();
          getWindowManager().getDefaultDisplay().getMetrics(metrics);
          w=d=(int)round(metrics.densityDpi);
          LinearLayout row1=row(true);
          LinearLayout row2=row(false);
          LinearLayout layout=new LinearLayout(this);
          layout.setOrientation(LinearLayout.VERTICAL);
          layout.addView(row1);
          layout.addView(row2);
          LinearLayout l=new LinearLayout(this);
          setContentView(layout);
      }
      @Override
      public boolean onCreateOptionsMenu(Menu menu) {
          return true;
      }
      public class DrawableView extends View {
          public DrawableView(Context context,int column,boolean isRow1) {
              super(context);
              setBackgroundColor(Color.TRANSPARENT);
              this.column=column;
              text=""+(char)('0'+column);
              int r=(int)round(w*radius);
              d0=new ShapeDrawable(new RoundRectShape(new float[]{r,r,r,r,r,r,r,r},null,null));
              d0.getPaint().setColor(0xff000000);
              d0.setBounds(0,0,w,d);
              d1=new ShapeDrawable(new RoundRectShape(new float[]{r,r,r,r,r,r,r,r},null,null));
              d1.getPaint().setColor(on[column]);
              d1.setBounds(edge,edge,w-edge,d-edge);
              d2=new ShapeDrawable(new RoundRectShape(new float[]{r,r,r,r,r,r,r,r},null,null));
              int b=(int)round(w*border);
              d2.setBounds(b/2,b/2,w-b/2,d-b/2);
              d2.getPaint().setColor(isRow1?on[column]:off[column]);
          }
          protected void onDraw(Canvas canvas) {
              d0.draw(canvas);
              d1.draw(canvas);
              d2.draw(canvas);
              Paint paint = new Paint();
              //paint.setColor(Color.WHITE);
              paint.setStyle(Paint.Style.FILL);
              //canvas.drawPaint(paint);
              paint.setColor(Color.CYAN);
              paint.setTextSize(w*95/100);
              Rect r=new Rect();
              paint.getTextBounds(text,0,1,r); // were switched
              canvas.drawRect(r,paint);  // were switched
              int x=(w-r.width())/2,y=(d-r.height())/2;
              paint.setColor(Color.BLACK);
              canvas.drawText(text,x,d-y,paint);
          }
          final int column;
          final String text;
          ShapeDrawable d0, d1, d2;
      }
      final int n=5, edge=1;
      double margin=.10, radius=.05, border=.15;
      int w, d;
      final int[] on=new int[]{0xffff0000,0xffffff00,0xff00ff00,0xff0000ff,0xffff8000};
      final int[] off=new int[]{0xff800000,0xff808000,0xff008000,0xff000080,0xff804000};
  }
  </code></pre>
  
  <p>This version tries to subclass drawable and use a button. but the button's drawing seems to interfere with drawing my drawable shapes. it looks like the bounds are being ignored.</p>
  
  <pre><code>package acme.drawables;
  import android.content.*;
  import android.content.pm.*;
  import android.graphics.*;
  import android.graphics.drawable.*;
  import android.graphics.drawable.shapes.*;
  import android.support.v7.app.AppCompatActivity;
  import android.os.Bundle;
  import android.util.*;
  import android.view.Menu;
  import android.view.View;
  import android.widget.*;
  
  import static java.lang.Math.*;
  public class MainActivity extends AppCompatActivity {
      LinearLayout row(boolean isRow1) {
          LinearLayout layout=new LinearLayout(this);
          layout.setOrientation(LinearLayout.HORIZONTAL);
          LinearLayout.LayoutParams layoutParams=new LinearLayout.LayoutParams(w,d);
          int m=(int)round(w*margin);
          layoutParams.setMargins(m,m,m,m);
          if(true)
              for(int i=0;i&lt;n;i++) { // subclass drawable
                  Button b=new Button(this);
                  b.setText(""+(char)('0'+i));
                  b.setBackground(new MyDrawable(i,i/n%2==0));
                  layout.addView(b,layoutParams);
              }
          else
              for(int i=0;i&lt;n;i++) // use drawable view with canvas draw text
                  layout.addView(drawableView=new DrawableView(i,isRow1),layoutParams);
          return layout;
      }
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
          DisplayMetrics metrics=new DisplayMetrics();
          getWindowManager().getDefaultDisplay().getMetrics(metrics);
          w=d=(int)round(metrics.densityDpi);
          LinearLayout row1=row(true);
          LinearLayout row2=row(false);
          LinearLayout layout=new LinearLayout(this);
          layout.setOrientation(LinearLayout.VERTICAL);
          layout.addView(row1);
          layout.addView(row2);
          LinearLayout l=new LinearLayout(this);
          setContentView(layout);
      }
      @Override
      public boolean onCreateOptionsMenu(Menu menu) {
          return true;
      }
      public class MyDrawable extends Drawable {
          public MyDrawable(int column,boolean isRow1) {
              drawableView=new DrawableView(column,isRow1);
          }
          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.");
              drawableView.d0.draw(canvas);
              System.out.println("d0 bounds: "+drawableView.d0.getBounds());
              drawableView.d1.draw(canvas);
              System.out.println("d1 bounds: "+drawableView.d1.getBounds());
              drawableView.d2.draw(canvas);
              System.out.println("d2 bounds: "+drawableView.d2.getBounds());
          }
          final DrawableView drawableView; // cheat by delegating
      }
      public class DrawableView extends View {
          public DrawableView(int column,boolean isRow1) {
              super(MainActivity.this);
              setBackgroundColor(Color.TRANSPARENT);
              this.column=column;
              text=""+(char)('0'+column);
              int r=(int)round(w*radius);
              d0=new ShapeDrawable(new RoundRectShape(new float[]{r,r,r,r,r,r,r,r},null,null));
              d0.getPaint().setColor(0xff000000);
              d0.setBounds(0,0,w,d);
              d1=new ShapeDrawable(new RoundRectShape(new float[]{r,r,r,r,r,r,r,r},null,null));
              d1.getPaint().setColor(on[column]);
              d1.setBounds(edge,edge,w-edge,d-edge);
              d2=new ShapeDrawable(new RoundRectShape(new float[]{r,r,r,r,r,r,r,r},null,null));
              int b=(int)round(w*border);
              d2.setBounds(b/2,b/2,w-b/2,d-b/2);
              d2.getPaint().setColor(isRow1?on[column]:off[column]);
          }
          protected void onDraw(Canvas canvas) {
              d0.draw(canvas);
              d1.draw(canvas);
              d2.draw(canvas);
              Paint paint=new Paint();
              //paint.setColor(Color.WHITE);
              paint.setStyle(Paint.Style.FILL);
              //canvas.drawPaint(paint);
              paint.setColor(Color.CYAN);
              paint.setTextSize(w*95/100);
              Rect r=new Rect();
              canvas.drawRect(r,paint);
              paint.getTextBounds(text,0,1,r);
              int x=(w-r.width())/2, y=(d-r.height())/2;
              paint.setColor(Color.BLACK);
              canvas.drawText(text,x,d-y,paint);
          }
          final int column;
          final String text;
          ShapeDrawable d0, d1, d2;
      }
      DrawableView drawableView;
      final int n=5, edge=1;
      double margin=.10, radius=.05, border=.15;
      int w, d;
      final int[] on=new int[]{0xffff0000,0xffffff00,0xff00ff00,0xff0000ff,0xffff8000};
      final int[] off=new int[]{0xff800000,0xff808000,0xff008000,0xff000080,0xff804000};
  }
  </code></pre>