我正在尝试根据用户实时指定的输入为我的Android应用程序实现动态按钮通胀。单击时,按钮会将其颜色从蓝色更改为红色。
负责此操作的代码如下:
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();
}
我追加按钮的布局是一个简单的LinearLayout
:
<LinearLayout
android:id="@+id/layout_for_buttons"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
</LinearLayout>
虚增的button_layout
是由RelativeLayout
和Button
组成的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
是蓝色的shape
:
<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>
现在,当我运行应用程序时,一切似乎都很好。点击后,第一个按钮不出所料变成红色:
当我关闭并重新运行应用程序时,每个按钮都是蓝色,这是符合我的期望的行为。问题是,当我第二次重新运行应用程序时,每个按钮都会变为红色(就好像它已被点击一样):
由于它是在文档中编写的,inflate
方法应该根据给定的XML扩展新的视图层次结构,那么可能对此负责?我认为每个膨胀按钮可以共享相同的GradientDrawable
,但调试器显示每个按钮都有自己的GradientDrawable
实例。
答案 0 :(得分:8)
似乎我已经解决了我的问题。这是一个GradientDrawable.mutate()
方法,必须调用它来防止这种行为:
Button button = (Button) buttonView;
GradientDrawable gradientDrawable = (GradientDrawable) button.getBackground();
gradientDrawable.mutate(); // needed line
gradientDrawable.setColor(Color.RED);
gradientDrawable.invalidateSelf();
它保证初始化的Drawable不会与从同一XML中膨胀的Drawable共享其状态,如documentation中所述:
使这个drawable可变。此操作无法逆转。一个可变的drawable保证不与任何其他drawable共享其状态。当您需要修改从资源加载的drawable的属性时,这尤其有用。默认情况下,从同一资源加载的所有drawables实例共享一个公共状态;如果修改一个实例的状态,则所有其他实例将收到相同的修改。在可变的Drawable上调用此方法将不起作用。
答案 1 :(得分:0)
在线性布局上调用invalidate
linearLayout.addView(buttonLayout);
linearLayout.invalidate();