禁用一个ImageButton

28

看起来很简单,但我无法禁用一个 ImageButton。它仍然会接收到点击事件,并且它的外观不像标准按钮那样改变。

在 SO 上有一些类似的问题,但它们对我没有帮助。

即使是这样一个非常简单的布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">

    <ImageButton
        android:id="@+id/btn_call"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:clickable="false"
        android:enabled="false"
        android:src="@android:drawable/sym_action_call" />

</LinearLayout>

奇怪的是,如果我将 ImageButton 更改为简单的 Button,那么它按预期工作。按钮变为不可用且无法点击。我不明白。是否有人有想法?

8个回答

48

这是我用来禁用一个 ImageButton 并使其看起来变灰的代码:

/**
 * Sets the specified image buttonto the given state, while modifying or
 * "graying-out" the icon as well
 * 
 * @param enabled The state of the menu item
 * @param item The menu item to modify
 * @param iconResId The icon ID
 */
public static void setImageButtonEnabled(Context ctxt, boolean enabled, ImageButton item,
        int iconResId) {
    item.setEnabled(enabled);
    Drawable originalIcon = ctxt.getResources().getDrawable(iconResId);
    Drawable icon = enabled ? originalIcon : convertDrawableToGrayScale(originalIcon);
    item.setImageDrawable(icon);
}

/**
 * Mutates and applies a filter that converts the given drawable to a Gray
 * image. This method may be used to simulate the color of disable icons in
 * Honeycomb's ActionBar.
 * 
 * @return a mutated version of the given drawable with a color filter
 *         applied.
 */
public static Drawable convertDrawableToGrayScale(Drawable drawable) {
    if (drawable == null) {
        return null;
    }
    Drawable res = drawable.mutate();
    res.setColorFilter(Color.GRAY, Mode.SRC_IN);
    return res;
}

直接调用setImageButtonEnabled()即可;唯一的缺点是需要在此处使用图像的资源ID,因为无法将转换后的图标恢复为原始状态。


20

ImageButton 的继承链不同,这意味着它没有继承 Button:

ImageButton < ImageView < View

它仍然能够接收点击事件。

当您为 View 设置点击监听器时,发生了以下情况:

public void setOnClickListener(OnClickListener l) {
    if (!isClickable()) {
        setClickable(true);
    }
    mOnClickListener = l;
}

如果你设置了一个监听器,android:clickable="false"将会变成android:clickable="true"。但是,它的外观不会像普通按钮那样改变。

你应该为视图提供一个可绘制状态列表,这样它就可以根据android:enabled设置适当的图像。你有这个吗?还是你的按钮只有一个图片?

编辑:您可以在此处找到有关StateListDrawable的信息(链接)。在列表中使用android:state_enabled即可告诉操作系统在该状态下使用什么图像。

编辑2:既然你真的需要添加一个监听器,你可以在监听器内部做一个检查:if (!isEnabled()) { return; } else { /* 处理事件 */ }


对我没用。帮助我的是通过代码设置禁用状态: ImageButton mBtnDelayCall =(ImageButton)v.findViewById(R.id.btnCallDelay); mBtnDelayCall.setEnabled(false); - user2924714

6

如果你想要禁用一个图片按钮,在点击事件中,将属性 "setEnabled" 设置为 false。

例如:imgButton.setEnabled(false);


2
android:enabled="false" 不起作用,但是在代码中使用 setEnabled() 方法设置属性可以生效。 - Silvia H

2

确保您的视图层次结构中没有相同ID的视图,并且您不会为该视图添加任何点击监听器。


2
利用 Oleg Vaskevich 的答案,可以为 Kotlin 制作一个答案。
为 ImageButton 制作一个扩展函数,方法如下:
/**
 * Sets the specified image buttonto the given state, while modifying or
 * "graying-out" the icon as well
 *
 * @param enabled The state of the menu item
 * @param iconResId The icon ID
 */
fun ImageButton.setButtonEnabled(enabled: Boolean, iconResId: Int) {
    isEnabled = enabled
    val originalIcon = context.resources.getDrawable(iconResId)
    val icon = if (enabled) originalIcon else convertDrawableToGrayScale(originalIcon)
    setImageDrawable(icon)
}

"并且你会变得更不依赖提供上下文的信息。"

1

我成功构建了一个受 Oleg Vaskevich 答案 启发的解决方案,但无需传递可绘制资源 ID 来设置 setEnabled()。

以下是 Kotlin 代码,在实用程序模块内:

fun Drawable.deepCopy(): Drawable =
    constantState?.newDrawable()?.mutate() ?:
        throw RuntimeException("Called on null Drawable!")

fun Drawable.toGrayscale(): Drawable =
        deepCopy().apply { setColorFilter(Color.GRAY, PorterDuff.Mode.SRC_IN) }

fun ImageButton.setAndShowEnabled(enabled: Boolean) {
    if (enabled == isEnabled)
        return

    isEnabled = enabled

    if (enabled) {
        setImageDrawable(tag as Drawable)
    }
    else {
        if (tag == null)
            tag = drawable

        setImageDrawable(drawable.toGrayscale())
    }
}

它可以这样使用:

val button: ImageButton = findViewById(...)
// ...
button.setAndShowEnabled(false)

// launch async operation
GlobalScope.launch {
    // do work here

    // unblock button
    button.setAndShowEnabled(true)
}

0
为了改进2018年Ivan的答案:这是一个更简单的方法(Kotlin):
   fun ImageButton.setAndShowEnabled(enabled: Boolean) {
    val filter = PorterDuffColorFilter(GRAY, PorterDuff.Mode.SCREEN)
    if (enabled == this.isEnabled)
        return

    this.isEnabled = enabled

    if (enabled) {
        drawable.colorFilter = null  // Removes the filter.
    } else {
        drawable.mutate()   // Repeated calls are no-ops.
        drawable.colorFilter = filter
    }
}

0

正如其他答案所述,您无法像Button一样在布局XML中禁用ImageButton,但是您可以在运行时以相同的方式禁用两者:

在Java中:

button.setEnabled(false);     // setEnabled(boolean) on TextView
imgButton.setEnabled(false);  // setEnabled(boolean) on View

在这两种情况下,按钮都被禁用了--没有点击事件会传递到它的onClickListener
您还可以通过与禁用Button上更改文本颜色相同的方式来更改禁用ImageButton的图标颜色,假设该图标是可着色的。
在布局XML中:
<Button
    ...
    android:textColor="@drawable/button_color_selector" />


<ImageButton
    ...
    android:tint="@drawable/button_color_selector" />

现在,在ButtonImageButton上调用setEnable(boolean)方法,会根据你的button_color_selector.xml中定义的状态改变文本或图标颜色。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接