改变一个人的颜色时膨胀按钮的奇怪行为

fal*_*epl 2 android layout-inflater android-view

我正在尝试根据用户实时指定的输入为我的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();
}
Run Code Online (Sandbox Code Playgroud)

我追加按钮的布局很简单LinearLayout:

<LinearLayout
    android:id="@+id/layout_for_buttons"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
</LinearLayout>
Run Code Online (Sandbox Code Playgroud)

膨胀button_layoutRelativeLayout由a Button和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>
Run Code Online (Sandbox Code Playgroud)

@drawable/button_bgshape蓝色的:

<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>
Run Code Online (Sandbox Code Playgroud)

现在,当我运行应用程序时,一切似乎都没问题.点击后,第一个按钮不出所料变成红色:

在此输入图像描述

当我关闭并重新运行应用程序时,每个按钮都是蓝色,这是符合我的期望的行为.问题是,当我第二次重新运行应用程序时,每个按钮都变为红色(就像它被点击一样):

在此输入图像描述

由于它是在文档中编写的,因此inflate方法应该基于给定的XML 来扩展新的视图层次结构,那么可以对此负责呢?我认为GradientDrawable每个膨胀按钮可以共享相同的内容,但调试器显示每个按钮都有自己的GradientDrawable实例.

fal*_*epl 8

看来我已经解决了我的问题.这是一种GradientDrawable.mutate()必须被调用来防止这种行为的方法:

Button button = (Button) buttonView;
GradientDrawable gradientDrawable = (GradientDrawable) button.getBackground();
gradientDrawable.mutate(); // needed line
gradientDrawable.setColor(Color.RED);
gradientDrawable.invalidateSelf();
Run Code Online (Sandbox Code Playgroud)

它保证初始化的Drawable不会与从同一XML中膨胀的Drawable共享其状态,如文档中所述:

使这个drawable可变.此操作无法逆转.一个可变的drawable保证不与任何其他drawable共享其状态.当您需要修改从资源加载的drawable的属性时,这尤其有用.默认情况下,从同一资源加载的所有drawables实例共享一个公共状态; 如果修改一个实例的状态,则所有其他实例将收到相同的修改.在可变的Drawable上调用此方法将不起作用.