Issue
I have create a custom Button
subclass which performs some custom drawing and adds some additional features.
Now I would like to add the possibility to show a custom drawable/image/icon on that Button
. Adding the image is not a big deal, but how can I tint this icon in different colors depending on the current state?
I tried to use a ColorStateList
to tint the drawable with the current state-color, but it does not work: The drawable is always drawn with its own, unchanged color.
I assume that the applied color filter is not used when converting the drawable into a bitmap. Is this correct? How can I fix this?
This is my code:
Layout
<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;
}
}
Solution
The error that you are seeing, "more restores than saves", means that you have called Canvas.restore()
more times than Canvas.save()
. You must have a matching restore for each save.
You don't show the saves and restores in your code, but make sure that they balance for all execution paths.
The underflow condition is cured. I think that you have a sizing/placement problem. Instead of converting the icon for your button to a bitmap, try the following:
mIconDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
mIconDrawable.draw(canvas);
You might be getting hung up in the conversion. If you really want to create the bitmap, I don't think that the intrinsic width and height are what you need. Try the following:
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;
}
Then call and draw the icon as follows:
Bitmap icon = drawableToBitmap(mIconDrawable, canvas.getWidth(), canvas.getHeight());
canvas.drawBitmap(icon, 0, 0, null);
Answered By - Cheticamp
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.