我创建了一个自定义Button
子类,它执行一些自定义绘图并添加了一些其他功能。
现在我想添加在Button
上显示自定义drawable / image /图标的可能性。添加图像并不是什么大问题,但是如何根据当前状态为不同颜色的图标着色?
我尝试使用ColorStateList
使用当前状态颜色对drawable进行着色,但它不起作用:drawable始终使用自己的未更改颜色绘制。
我假设在将drawable转换为位图时不使用应用的滤色器。它是否正确?我该如何解决这个问题?
这是我的代码:
布局
<com.example.UI.MyButton
...
mc:iconSrc="@drawable/someIcon"
mc:iconTintColor="@drawable/button_selector_colors"/>
attrs.xml
<declare-styleable name="MyButton">
<attr name="iconSrc" format="reference" />
<attr name="iconTintColor" format="reference" />
</declare-styleable>
button_selector_colors.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:color="@color/myPressed"/>
<item android:state_selected="true" android:color="@color/mySelected"/>
<item android:color="@color/myDefault"/>
</selector>
MyButton.java
public class MyButton extends Button {
private Drawable mIconDrawable;
private ColorStateList mIconTintColor;
public MyButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs);
}
public MyButton(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MyButton);
for (int i = 0; i < array.getIndexCount(); ++i) {
int attr = array.getIndex(i);
switch (attr) {
case R.styleable.MyButton_iconSrc:
mIconDrawable = array.getDrawable(attr);
break;
case R.styleable.MyButton_iconTintColor:
mIconTintColor = array.getColorStateList(attr);
break;
default:
break;
}
}
array.recycle();
}
@Override
protected void onDraw(Canvas canvas) {
...
if (mIconDrawable != null) {
... // calc position, etc.
if (mIconTintColor != null) {
mIconDrawable.mutate();
int[] stateSet = getDrawableState();
int defaultColor = Color.BLACK; //mIconTintColor.getDefaultColor();
int stateColor = mIconTintColor.getColorForState(stateSet, defaultColor);
mIconDrawable.setColorFilter(stateColor, PorterDuff.Mode.SRC_ATOP);
}
Bitmap icon = drawableToBitmap(mIconDrawable);
canvas.drawBitmap(icon, ...);
}
}
public static Bitmap drawableToBitmap (Drawable drawable) {
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable)drawable).getBitmap();
}
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
}
答案 0 :(得分:1)
您看到的错误“恢复比保存更多”意味着您调用的Canvas.restore()
次数超过Canvas.save()
。每次保存都必须有匹配的恢复。
您不会在代码中显示保存和恢复,但请确保它们平衡所有执行路径。
下溢情况得到治愈。我认为你有尺码/贴装问题。不要将按钮的图标转换为位图,而是尝试以下操作:
mIconDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
mIconDrawable.draw(canvas);
您可能会在转换中陷入困境。如果你真的想创建位图,我不认为你需要的内在宽度和高度。请尝试以下方法:
public static Bitmap drawableToBitmap(Drawable drawable, int width, int height) {
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
}
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
然后按如下方式调用并绘制图标:
Bitmap icon = drawableToBitmap(mIconDrawable, canvas.getWidth(), canvas.getHeight());
canvas.drawBitmap(icon, 0, 0, null);