【问题标题】:Strange behavior of inflated buttons when changing one's color改变颜色时膨胀按钮的奇怪行为
【发布时间】:2013-05-02 19:01:00
【问题描述】:

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

<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 实例。

【问题讨论】:

    标签: android android-view layout-inflater


    【解决方案1】:

    看来我的问题已经解决了。那是一个 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 上调用此方法将无效。

    【讨论】:

    • 当我写了和你类似的代码时,我怀疑我会遇到像你这样的问题)并感谢你的回答
    【解决方案2】:

    添加视图后在线性布局上调用 invalidate,

    linearLayout.addView(buttonLayout);
    linearLayout.invalidate();
    

    【讨论】:

    • 我在linearLayout 上添加了invalidate 调用,但按钮的奇怪行为保持不变。
    • 尝试在您的活动父布局上调用 invalidate。
    • 不幸的是它也没有帮助。
    • 尝试在 onClick() 中调用 invalidate。
    • 好的,问题解决了。应该调用的是 mutate() 方法,而不是 invalidate()
    猜你喜欢
    • 1970-01-01
    • 2013-02-27
    • 1970-01-01
    • 1970-01-01
    • 2012-04-06
    • 1970-01-01
    • 2015-11-23
    • 2015-02-02
    • 1970-01-01
    相关资源
    最近更新 更多