2015-12-04 19 views
15

我想制作一个自定义按钮,就像这个程序可能使用径向渐变。Android - 自定义按钮,带有形状绘图和渐变编程

我创建了子视图,然后绘制三个形状的drawable,然后绘制文本。文字似乎偏离中心,所以我试图为文字画出一个边界矩形,但没有运气。并计划添加一个点击侦听器来获取类似按钮的行为。

也许我应该继承按钮,但是在哪里绘制我的drawable,这样它们就不会被绘制的按钮的文本弄乱。

任何指针将不胜感激。

谢谢

编辑2:请参阅下面的第二次尝试。

编辑3:赏金的原因是找出为什么子类drawable不起作用。渐变并不重要。

edit4:在DrawableView :: OnDraw()中的getTextBounds()之前发现了drawRect。

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

此版本试图绘制子类并使用按钮。但按钮的绘图似乎干扰绘制我的可绘制形状。它看起来像界限被忽略。

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

所有你需要的是什么,是创建一个自定义的'Drawable'类 – pskink

+0

您可以绘制使用梯度文件,并设置为背景 – curiousMind

+0

@pskink,所以我继承和绘制给它设置背景的buttton? –

回答

4

1)使用对齐画在中心文本在DrawableView(应帮助文本似乎偏离中心):

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

2)要回答你的问题赏金的理由是弄清楚为什么继承drawable不会w扫

我想这是因为你创建MyDrawableDrawableView,并且不将其添加到这意味着你没有衡量和布局没有任何容器。所以,它可能是零高度和宽度。

3)我建议你使用Button而不是自定义视图和drawables。您可以从按键中的onDraw方法端延伸,做更多的图纸,像这样:

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

原始错误的答案

为赏金的原因是为了弄清楚为什么子类化绘制不不行

尝试检查,如果你需要调用:

  • super.onDraw(canvas)DrawableView.onDraw
  • super.draw(canvas)MyDrawable.draw
+0

super.draw()在MyDrawable中是抽象的。 –

+0

DrawableView中没有super.OnDraw()。 –

+0

@RayTayek更新了我的答案,修复了无定制可绘制文本的居中定位的可能答案,以解释为什么可绘制子类不适用于您的案例和小建议。 – GregoryK

2

使用这个代码,以使渐变按钮

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); 
+0

我想以编程方式做到这一点。 –

2

这不是为了创造可绘制依赖于一个视图是一个好主意。按照Eugen Pechanec的建议,使MyDrawable和DrawableView成为静态。

您只在MyDrawable中使用ShapeDrawable,因此您可以将它从DrawableView中移出。

它可以是这样的:

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

你可以考虑不使用ShapeDrawable和自己绘制形状:

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

顺便说一句,这是很好的使用StateListDrawable为一个按钮。
所以,你可以使用MyDrawable这样的:

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); 
+0

现在这两个类都是静态的。如果我真的想要一个奇特的按钮,我会把这个垃圾从头开始。和子类按钮,也许使用可绘制的状态列表。谢谢 –

+0

如果你只是想改变它的设计,就不需要子类化Button。 Button扩展了TextView,因此您还可以轻松控制文本外观。但是如果你想改变字体,你需要继承它。 –

+0

我希望改变字体的大小,也许字体本身。 –