Android - 带有可绘制形状和渐变的自定义按钮
Android - custom button with shape drawables and a gradient programmatically
我想制作一个自定义按钮,就像这个程序所做的那样,可能使用径向渐变。
我将视图子类化,绘制三个形状的可绘制对象,然后绘制文本。文本似乎偏离了中心,所以我试图为文本绘制一个边界矩形,但没有成功。并计划添加一个点击监听器来获得类似按钮的行为。
也许我应该将按钮子类化,但在哪里绘制我的可绘制对象,这样它们就不会被正在绘制的按钮文本弄乱。
任何指点将不胜感激。
谢谢
Edit2:见下面的第二次尝试。
Edit3:悬赏的原因是要弄清楚为什么子类化 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};
}
使用此代码制作渐变按钮
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);
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 不起作用的原因:
我想这是因为您在 MyDrawable
中创建了 DrawableView
并且没有将其添加到任何容器中,这意味着您没有对其进行测量和布局。所以,它的高度和宽度可能为零。
3) 我建议您使用 Button 而不是自定义视图和可绘制对象。你从 Button 扩展并在 onDraw 方法的末尾做额外的绘图,像这样:
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
// your custom drawing over button
}
原来的错误答案
赏金的原因是想弄清楚为什么子类化drawable不起作用
试试看是否需要打电话:
super.onDraw(canvas)
在 DrawableView.onDraw
super.draw(canvas)
在 MyDrawable.draw
依赖View创建Drawable不是一个好主意。
正如 Eugen Pechanec 建议的那样,将 MyDrawable 和 DrawableView 设为静态。
您仅在 MyDrawable 中使用 ShapeDrawables,因此您可以将其从 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);
}
}
对了,Button用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);
我想制作一个自定义按钮,就像这个程序所做的那样,可能使用径向渐变。
我将视图子类化,绘制三个形状的可绘制对象,然后绘制文本。文本似乎偏离了中心,所以我试图为文本绘制一个边界矩形,但没有成功。并计划添加一个点击监听器来获得类似按钮的行为。
也许我应该将按钮子类化,但在哪里绘制我的可绘制对象,这样它们就不会被正在绘制的按钮文本弄乱。
任何指点将不胜感激。
谢谢
Edit2:见下面的第二次尝试。
Edit3:悬赏的原因是要弄清楚为什么子类化 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};
}
使用此代码制作渐变按钮
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);
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 不起作用的原因:
我想这是因为您在 MyDrawable
中创建了 DrawableView
并且没有将其添加到任何容器中,这意味着您没有对其进行测量和布局。所以,它的高度和宽度可能为零。
3) 我建议您使用 Button 而不是自定义视图和可绘制对象。你从 Button 扩展并在 onDraw 方法的末尾做额外的绘图,像这样:
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
// your custom drawing over button
}
原来的错误答案
赏金的原因是想弄清楚为什么子类化drawable不起作用
试试看是否需要打电话:
super.onDraw(canvas)
在DrawableView.onDraw
super.draw(canvas)
在MyDrawable.draw
依赖View创建Drawable不是一个好主意。 正如 Eugen Pechanec 建议的那样,将 MyDrawable 和 DrawableView 设为静态。
您仅在 MyDrawable 中使用 ShapeDrawables,因此您可以将其从 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);
}
}
对了,Button用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);