I am trying to implement a dynamic button inflation for my Android application, based on an input specified by the user in real time. When clicked, button changes its color from blue to red.
The code responsible for this goes as follows:
LayoutInflater layoutsInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
LinearLayout linearLayout = (LinearLayout) findViewById(R.id.layout_for_buttons);
// Let's say that now we need only 3 buttons:
for (int i = 0; i < 3; i++) {
RelativeLayout buttonLayout = (RelativeLayout) layoutsInflater
.inflate(R.layout.button_layout, linearLayout, false);
Button button = (Button) buttonLayout.getChildAt(0);
button.setText("Button " + i);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View buttonView) {
Button button = (Button) buttonView;
GradientDrawable gradientDrawable = (GradientDrawable) button
.getBackground();
gradientDrawable.setColor(Color.RED);
gradientDrawable.invalidateSelf();
}
});
linearLayout.addView(buttonLayout);
linearLayout.invalidate();
}
Layout that I append buttons to is a simple LinearLayout
:
<LinearLayout
android:id="@+id/layout_for_buttons"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
</LinearLayout>
Inflated button_layout
is a RelativeLayout
consisting of a Button
and a TextView
:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10sp" >
<Button
android:id="@+id/button_view"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/button_bg"
android:gravity="left"
android:paddingBottom="7dip"
android:paddingLeft="50sp"
android:paddingTop="7dip"
android:textColor="#FFFFFF"
android:textSize="20sp" />
<TextView
android:id="@+id/label_view"
android:layout_width="24dip"
android:layout_height="24dip"
android:layout_marginLeft="13dip"
android:layout_marginTop="8dip"
android:gravity="center"
android:text="Hi"
android:textColor="#FFFFFF"
android:textSize="20sp"
android:textStyle="bold" />
</RelativeLayout>
@drawable/button_bg
is a shape
in blue color:
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:padding="10dp"
android:shape="rectangle" >
<solid android:color="#0000ff" />
<corners android:radius="10dp" />
</shape>
Now, when I run the application everything seems to be fine. After being clicked, first button unsurprisingly turns red:
When I close and re-run the application every single button is blue, and that is a behavior that matches up to my expectations. The problem is, when I re-run the application for the second time, every button turns red (as if it has been clicked):
As it is written in a documentation, inflate
method should inflate a new view hierarchy based on a given XML, so what could be responsible for this? I thought that the same GradientDrawable
might be shared among every inflated button, but debugger shows that each button has its own GradientDrawable
instance.
It seems that I've already solved my problem. That was a
GradientDrawable.mutate()
method which had to be called to prevent such behavior:It guarantees that an initialized Drawable won't share its state with Drawables inflated from the same XML, as it was stated in a documentation:
call invalidate on linear layout after adding the view,