问题
This looks easy, but I'm not able to disable an ImageButton
. It continues to receive click events, and its appearance don't change like a standard Button would.
There are some similar questions on SO, but they don't help me.
Even with a very simple layout like this :
<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>
The button is still enabled and I can click it.
What's strange is that if I change the ImageButton
to a simple Button
, then it works as expected. The button becomes disabled and unclickable. I don't understand. Does anyone have an idea?
回答1:
ImageButton
has different inheritance chain meaning it does not extend Button
:
ImageButton
< ImageView
< View
It continues to receive click events
Here is what happens when you set a click listener for the View
:
public void setOnClickListener(OnClickListener l) {
if (!isClickable()) {
setClickable(true);
}
mOnClickListener = l;
}
So if you set a listener the android:clickable="false"
changes to android:clickable="true"
.
and its appearance don't change like a standard Button would
You should supply a drawable state list to the view so it could set an appropriate image based on android:enabled
. Do you have this? Or you have the only image for your button?
EDIT: You can find info on StateListDrawable here. android:state_enabled
is what you need to use in the list in order to tell the OS what image to use for that state.
EDIT2: Since you really need to add a listener you can make a check inside of the listener if (!isEnabled()) { return; } else { /* process the event */ }
.
回答2:
Here's the code I use to disable an ImageButton
and make it look grayed out:
/**
* 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;
}
Simply call setImageButtonEnabled()
; the only downside is you need the image's resource ID in here because it's not possible to revert a transformed icon back into the original.
回答3:
Make sure there is no view with same id in your view hierarchy and you do not add any click listener to that view.
回答4:
if you want to disable an image button,on click event, set the the property "setEnabled" to false
Ex: imgButton.setEnabled(false);
回答5:
Taking advantage of the Oleg Vaskevich's answer. Can be made an answer for Kotlin.
Make a Extension Function for ImageButton, this way:
/**
* 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)
}
And you get a little less reliant on providing Context
回答6:
I managed to build a solution inspired by Oleg Vaskevich's answer, but without the need to pass drawable resource ID to setEnabled().
Here is Kotlin code, inside of utility module:
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())
}
}
It can be used like this:
val button: ImageButton = findViewById(...)
// ...
button.setAndShowEnabled(false)
// launch async operation
GlobalScope.launch {
// do work here
// unblock button
button.setAndShowEnabled(true)
}
回答7:
As other answers have said, you cannot disable an ImageButton
in the layout XML as you can a Button
, but you can disable both the same way at runtime:
In Java:
button.setEnabled(false); // setEnabled(boolean) on TextView
imgButton.setEnabled(false); // setEnabled(boolean) on View
In both cases the button is disabled -- no click events get to its onClickListener
.
You can also change the icon color of the disabled ImageButton
the same way you change the text color on a disabled Button
, assuming the icon is tintable.
In the layout XML:
<Button
...
android:textColor="@drawable/button_color_selector" />
<ImageButton
...
android:tint="@drawable/button_color_selector" />
Now setEnable(boolean)
on the Button
or ImageButton
changes the text or icon color according to the states in your button_color_selector.xml
来源:https://stackoverflow.com/questions/8196206/disable-an-imagebutton