¿Botón de imagen de Android con un estado seleccionado?

87

Si estaba usando un ImageButton con un selector para su fondo, ¿hay algún estado que pueda cambiar que haga que cambie su apariencia? Ahora mismo puedo hacer que cambie las imágenes cuando se presiona, pero parece que no hay ningún estado "resaltado" o "seleccionado" o similar que me permita alternar su apariencia a voluntad.

Aquí está mi XML; solo cambia de apariencia cuando se presiona.

 <selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true" android:state_pressed="false" android:drawable="@drawable/map_toolbar_details_selected" />
<item android:state_focused="true" android:state_pressed="true" android:drawable="@drawable/map_toolbar_details_selected" />
<item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/map_toolbar_details_selected" />
<item android:drawable="@drawable/map_toolbar_details" />

Joren
fuente
1
Usar un ImageButton y rastrear el estado seleccionado parece un poco complicado. Debe usar un botón de alternancia, si desea alternar la funcionalidad.
Andras Balázs Lajtha

Respuestas:

214

Esto funciona para mi:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- NOTE: order is important (the first matching state(s) is what is rendered) -->
    <item 
        android:state_selected="true" 
        android:drawable="@drawable/info_icon_solid_with_shadow" />
    <item 
        android:drawable="@drawable/info_icon_outline_with_shadow" />
 </selector>

Y luego en java:

//assign the image in code (or you can do this in your layout xml with the src attribute)
imageButton.setImageDrawable(getBaseContext().getResources().getDrawable(R.drawable....));

//set the click listener
imageButton.setOnClickListener(new OnClickListener() {

    public void onClick(View button) {
        //Set the button's appearance
        button.setSelected(!button.isSelected());

        if (button.isSelected()) {
            //Handle selected state change
        } else {
            //Handle de-select state change
        }

    }

});

Para una transición suave, también puede mencionar el tiempo de animación:

<selector xmlns:android="http://schemas.android.com/apk/res/android" android:exitFadeDuration="@android:integer/config_mediumAnimTime">
Joshrl
fuente
3
Esto funcionó para mí, pero me gustaría agregar que uno debe crear este xml en su carpeta dibujable y si desea que ImageButton se resalte cuando se presiona, debe usar android: state_pressed en lugar de state_selected. Además, este estado debe estar por encima de un elemento sin estado, ya que es menos general.
Denis Kutlubaev
3
NOTE: order is important (the first matching state(s) is what is renderedesto funcionó pero extraño no entendí POR QUÉ?
Muhammad Babar
2
En ausencia de atributos de estado, el elemento coincidirá con cualquier estado. Así que piense en el segundo elemento del selector como el estado "capturar todo".
joshrl
2
El pedido no es importante, ¡solo debe asegurarse de proporcionar android:state_selected="false" el predeterminado!
Muhammad Babar
¿Cómo puedo hacer lo mismo en un widget? Tengo un botón, pero parece que no puedo averiguar cómo hacerlo.
Si8
19

ToggleImageButtonque implementa Checkableinterfaz y soporte OnCheckedChangeListenery android:checkedatributo xml:

public class ToggleImageButton extends ImageButton implements Checkable {
    private OnCheckedChangeListener onCheckedChangeListener;

    public ToggleImageButton(Context context) {
        super(context);
    }

    public ToggleImageButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        setChecked(attrs);
    }

    public ToggleImageButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setChecked(attrs);
    }

    private void setChecked(AttributeSet attrs) {
        TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ToggleImageButton);
        setChecked(a.getBoolean(R.styleable.ToggleImageButton_android_checked, false));
        a.recycle();
    }

    @Override
    public boolean isChecked() {
        return isSelected();
    }

    @Override
    public void setChecked(boolean checked) {
        setSelected(checked);

        if (onCheckedChangeListener != null) {
            onCheckedChangeListener.onCheckedChanged(this, checked);
        }
    }

    @Override
    public void toggle() {
        setChecked(!isChecked());
    }

    @Override
    public boolean performClick() {
        toggle();
        return super.performClick();
    }

    public OnCheckedChangeListener getOnCheckedChangeListener() {
        return onCheckedChangeListener;
    }

    public void setOnCheckedChangeListener(OnCheckedChangeListener onCheckedChangeListener) {
        this.onCheckedChangeListener = onCheckedChangeListener;
    }

    public static interface OnCheckedChangeListener {
        public void onCheckedChanged(ToggleImageButton buttonView, boolean isChecked);
    }
}

res / valores / attrs.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="ToggleImageButton">
        <attr name="android:checked" />
    </declare-styleable>
</resources>
vokilam
fuente
2
¿Como puedo usar lo? Seguí las instrucciones en: developer.android.com/training/custom-views/create-view.html pero no pude hacer que funcionara.
atisman
2
¡Gracias! Sin state_checkedembargo, tenga en cuenta que un selector con no funciona con esto, debe usar state_selected.
Florian von Stosch
11

La mejor forma de hacer esto sin más imágenes:

public static void buttonEffect(View button){
    button.setOnTouchListener(new OnTouchListener() {

        public boolean onTouch(View v, MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN: {
                    v.getBackground().setColorFilter(0xe0f47521,PorterDuff.Mode.SRC_ATOP);
                    v.invalidate();
                    break;
                }
                case MotionEvent.ACTION_UP: {
                    v.getBackground().clearColorFilter();
                    v.invalidate();
                    break;
                }
            }
            return false;
        }
    });
}
András
fuente
1
puede usar getResources (). getColor (R.color.lightblue) para colorear desde su xml.
Beto Caldas
@ András necesita mantener el botón presionado un poco más. ¿Sabes por qué es eso?
lionelmessi
3

Cree un archivo XML en una res/drawablecarpeta. Por ejemplo, "btn_image.xml":

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/bg_state_1"
          android:state_pressed="true"
          android:state_selected="true"/>
    <item android:drawable="@drawable/bg_state_2"
          android:state_pressed="true"
          android:state_selected="false"/>
    <item android:drawable="@drawable/bg_state_selected"
          android:state_selected="true"/>
    <item android:drawable="@drawable/bg_state_deselected"/>
</selector>

Puede combinar los archivos que desee, por ejemplo, cambiar "bg_state_1" a "bg_state_deselected" y "bg_state_2" a "bg_state_selected".

En cualquiera de esos archivos puede escribir algo como:

<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="rectangle">
    <solid android:color="#ccdd00"/>
    <corners android:radius="5dp"/>
</shape>

Cree en un archivo de diseño un ImageView o ImageButton con los siguientes atributos:

<ImageView
    android:id="@+id/image"
    android:layout_width="50dp"
    android:layout_height="50dp"
    android:adjustViewBounds="true"
    android:background="@drawable/btn_image"
    android:padding="10dp"
    android:scaleType="fitCenter"
    android:src="@drawable/star"/>

Más adelante en el código:

image.setSelected(!image.isSelected());
CoolMind
fuente
2

Prueba esto:

 <item
   android:state_focused="true"
   android:state_enabled="true"
   android:drawable="@drawable/map_toolbar_details_selected" />

También para los colores con los que tuve éxito

<selector
        xmlns:android="http://schemas.android.com/apk/res/android">
        <item
            android:state_selected="true"

            android:color="@color/primary_color" />
        <item
            android:color="@color/secondary_color" />
</selector>
Alex Volovoy
fuente
Hmm. No parece ayudar. Estoy usando un CompoundButton. ¿Existe un estado específico para ese tipo de botón de encendido / apagado?
Joren
Sí, se llama verificado, consulte isChecked () developer.android.com/reference/android/widget/…
Bostwickenator
0
if (iv_new_pwd.isSelected()) {
                iv_new_pwd.setSelected(false);
                Log.d("mytag", "in case 1");
                edt_new_pwd.setInputType(InputType.TYPE_CLASS_TEXT);
            } else {
                Log.d("mytag", "in case 1");
                iv_new_pwd.setSelected(true);
                edt_new_pwd.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
            }
MEGHA DOBARIYA
fuente