Reputation: 8350
I extended the Button widget to be able to apply several custom attributes.
One of the attributes is a color filter I try to apply to its background when the button is created. It does not work. (See the screen shots and code below)
I tried to directly set the background color, on the same code place, and it does change the background color, but it is not what I need, since I am using my own button PNGs.
there are 2 problems so far:
The second button uses the normal button, and it is positioned as expected and it is clickable. The second screenshot shows that the correct color is indeed chosen, and that it is possible to change the button background color at that point in the code.
Code:
public class MyButton extends Button {
private int backGroundColor;
public MyButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.MyButton,
defStyle,
0);
try {
Resources res = getResources();
switch( a.getInteger(R.styleable.MyButton_type, 0) ) {
case 0:
backGroundColor = res.getColor(R.color.Black); break;
case 1:
backGroundColor = res.getColor(R.color.Red); break;
case 2:
backGroundColor = res.getColor(R.color.DimGray); break;
}
getBackground().setColorFilter(backGroundColor, Mode.MULTIPLY);
//setBackgroundColor(backGroundColor)
} finally {
a.recycle();
}
}
public MyButton(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyButton(Context context) {
this(context, null, 0);
}
}
The XML I used:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.example.test.MyButton
android:id="@+id/btn1"
android:text="BTN1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="14sp"
android:textColor="@color/Blue"
android:padding="2dp"
android:layout_margin="4dp"
android:background="@drawable/key_selector"
app:type="RedButton"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="14sp"
android:textColor="@color/Blue"
android:padding="2dp"
android:layout_margin="4dp"
android:background="@drawable/key_selector"
android:id="@+id/btn2"
android:text="BTN2"/>
</LinearLayout>
Screenshot of setColorFilter() outcome
Screenshot of setBackgroundColor() outcome
EDIT This is the selector XML I use for the normal and pressed states.
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:drawable="@drawable/key1_pressed"
android:state_pressed="true"/>
<item
android:drawable="@drawable/key1"/>
</selector>
Upvotes: 0
Views: 1027
Reputation: 87064
The custom button is offset, clipped and it is not clickable
That's due to your use of the constructors. The Button
class does chain between its constructors but it doesn't pass 0
to the last constructor as the style(from the second constructor which is the one used), it passes an internal style(what makes a visual Button
in the end). If you were to pass:
this(context, attrs, android.R.attr.buttonStyle);
the Button
should be ok.
The color filter is not applied
The code for setting the color filter should work with no problems after you make the correction above. When you'll set the filter you'll see that both buttons will have the filter applied to them(as they have the same bitmap(I'm assuming you use an image)). This is happening because the drawables of the same type share a constant state. You can read more from Romain Guy's explanation here:
getBackground().mutate().setColorFilter(backGroundColor, Mode.MULTIPLY);
Let me know if this solves the problem(from what I understood):
public static class MyButton extends Button {
private int backGroundColor;
private StateListDrawable mSld;
private PorterDuffColorFilter mColorFilter;
private boolean mHandled = false;
public MyButton(Context context, AttributeSet attrs, int defStyle) {
// ...
try {
//...
mSld = (StateListDrawable) getBackground();
mColorFilter = new PorterDuffColorFilter(backGroundColor,
Mode.MULTIPLY);
mSld.setColorFilter(mColorFilter);
} finally {
a.recycle();
}
}
@Override
protected void onDraw(Canvas canvas) {
if (!mHandled) {
final Drawable current = mSld.getCurrent();
current.mutate();
current.setColorFilter(mColorFilter);
mHandled = true;
}
super.onDraw(canvas);
}
}
Upvotes: 1