android - 改变颜色时充气按钮的奇怪行为

标签 android android-view layout-inflater

我正在尝试根据用户实时指定的输入为我的 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>

Inflated 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 xmlns:android="http://schemas.android.com/apk/res/android"
    android:padding="10dp"
    android:shape="rectangle" >
    <solid android:color="#0000ff" />
    <corners android:radius="10dp" />
</shape>

现在,当我运行应用程序时,一切似乎都很好。单击后,第一个按钮不出所料变为红色:

enter image description here

当我关闭并重新运行应用程序时,每个按钮都是蓝色的,这符合我的预期。问题是,当我第二次重新运行应用程序时,每个按钮都变成红色(好像已被单击):

enter image description here

正如文档中所写,inflate 方法应该根据给定的 XML 膨胀一个新的 View 层次结构,那么什么可能对此负责?我认为相同的 GradientDrawable 可能会在每个膨胀按钮之间共享,但调试器显示每个按钮都有自己的 GradientDrawable 实例。

最佳答案

看来我的问题已经解决了。这是一个必须调用以防止此类行为的 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 中所述:

Make this drawable mutable. This operation cannot be reversed. A mutable drawable is guaranteed to not share its state with any other drawable. This is especially useful when you need to modify properties of drawables loaded from resources. By default, all drawables instances loaded from the same resource share a common state; if you modify the state of one instance, all the other instances will receive the same modification. Calling this method on a mutable Drawable will have no effect.

关于android - 改变颜色时充气按钮的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16345756/

相关文章:

跨应用程序的 Android AccountManager : uninstalling the first app that registered the account causes the account to be deleted?

java - 如何使用 id 在 URL android 中传递 "?",因为我的 url 如下所示

android - 我如何从自定义 View 中获取宽度和高度尺寸?

c# - 将 Android MediaPlayer 与 C#Shell 结合使用

android - IllegalStateException:当我第二次尝试显示 AlertDialog 时

Android: View 嵌入在布局中。 onDraw() 方法被触发但屏幕没有立即更新

java - 包裹 android.os.Parcel@72a6e36 : Unmarshalling unknown type code 2131365270 at offset 500

android - 使用 LayoutInflator 的膨胀方法时的不同结果

安卓.view.InflateException : Binary XML file line #94: Error inflating class

android - 以编程方式在 Fragment 中扩充 XML