¿Cómo activar onListItemClick en Listactivity con botones en la lista?

89

Tengo una ListActivity simple que usa un ListAdapter personalizado para generar las vistas en la lista. Normalmente, ListAdapter solo llenaría las vistas con TextViews, pero ahora también quiero poner un botón allí.

Sin embargo, tengo entendido y experiencia que poner una vista enfocable en el elemento de la lista evita la activación de onListItemClick () en ListActivity cuando se hace clic en el elemento de la lista. El botón todavía funciona normalmente dentro del elemento de la lista, pero cuando se presiona algo además del botón, quiero que se active onListItemClick.

¿Cómo puedo hacer que esto funcione?

CodeFusionMobile
fuente
5
su solución con Focusability descendiente es realmente útil, ¡debe agregarla como respuesta y aceptarla!
Maksym Gontar
@Max La razón por la que no lo hago es porque es una mala práctica, una solución. Si alguna vez encontrara una solución saludable permanente, la haría una respuesta (si recuerdo que escribí esta pregunta hace un año :))
CodeFusionMobile
También me gustaría ver la solución alternativa que tiene. He intentado establecer el enfoque descendiente y no puedo hacer que funcione con los botones. También he intentado poner un GridView (con ImageViews) en la fila de la lista y eso tiene problemas similares.
MrPurpleStreak
En mi humilde opinión, la respuesta que di es una solución para el problema mucho más elegante que la propuesta por Ramps y Praveen. No estoy tratando de revivir la pregunta olvidada aquí, pero veo que aún no aceptó ninguna respuesta; D
Ewoks
@CodeFusionMobile ¿Podría aceptar la respuesta de Ewoks? La respuesta más votada tiene fallas porque deshabilita la animación al hacer clic para el elemento ListView (donde se vuelve azul). Les ahorraría a otros desarrolladores algo de tiempo para probar la respuesta principal, descubrir que tiene fallas y luego ir a Ewoks.
1 ''

Respuestas:

99

como escribí en el comentario anterior, la solución es setFocusable (false) en ImageButton.

Hay una solución aún más elegante que intenta agregar android:descendantFocusability="blocksDescendants" en el diseño de la raíz del elemento de la lista. Eso hará que los clics enListItem sean posibles y, por separado, puede manejar los clics de Button o ImageButton

Espero eso ayude ;)

Salud

Ewoks
fuente
3
android:descendantFocusability="blocksDescendants"fue perfecto.
Matthew Mitchell
1
tú, amigo mío, eres mi héroe personal. ¡deberías ser el mejor votado! ¡esto es mucho mejor para casi todos los casos!
OschtärEi
Esta debería ser la respuesta aceptada. Funcionó perfectamente para mí. Parece que todas las vistas en el elemento de la lista deben ser desenfocadas y esta hace precisamente eso sin configurar cada una individualmente.
rushinge
1
Esto no parece funcionar para mí. Por diseño raíz, ¿te refieres al diseño de filas o donde se define la vista de lista? De todos modos, probé todas las combinaciones posibles ... no funciona :(
GreenBee
"Diseño raíz del elemento de lista", como escribí. Digamos que tiene una lista y que consta de diseños (llámelos diseño raíz del elemento de lista) que tienen varios Button, ImageButton, TextVeiw ..
Ewoks
59

Espero poder ayudar aquí. Supongo que tiene un diseño personalizado para los elementos de listView, y este diseño consta de un botón y algunas otras vistas, como TextView, ImageView o lo que sea. Ahora desea que se active un evento diferente al hacer clic en el botón y que se active un evento diferente en todo lo demás.

Puede lograrlo sin usar onListItemClick () de su ListActivity.
Esto es lo que tienes que hacer:

Está utilizando un diseño personalizado, por lo que probablemente esté anulando el método getView () de su adaptador personalizado. El truco consiste en establecer diferentes oyentes para su botón y diferentes para toda la vista (su fila). Mira el ejemplo:

private class MyAdapter extends ArrayAdapter<String> implements OnClickListener {

    public MyAdapter(Context context, int resource, int textViewResourceId,
            List<String> objects) {
        super(context, resource, textViewResourceId, objects);
    }


    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        String text = getItem(position);
        if (null == convertView) {
            convertView = mInflater.inflate(R.layout.custom_row, null);
        }
        //take the Button and set listener. It will be invoked when you click the button.
        Button btn = (Button) convertView.findViewById(R.id.button);
        btn.setOnClickListener(this);
        //set the text... not important     
        TextView tv = (TextView) convertView.findViewById(R.id.text);
        tv.setText(text);
        //!!! and this is the most important part: you are settin listener for the whole row
        convertView.setOnClickListener(new OnItemClickListener(position));
        return convertView;
    }

    @Override
    public void onClick(View v) {
        Log.v(TAG, "Row button clicked");
    }
}

Su clase OnItemClickListener podría declararse como aquí:

private class OnItemClickListener implements OnClickListener{       
    private int mPosition;
    OnItemClickListener(int position){
        mPosition = position;
    }
    @Override
    public void onClick(View arg0) {
        Log.v(TAG, "onItemClick at position" + mPosition);          
    }       
}

Por supuesto, probablemente agregará algunos parámetros más al constructor OnItemClickListener.
Y una cosa importante: la implementación de getView que se muestra arriba es bastante fea, normalmente debería usar el patrón ViewHolder para evitar llamadas a findViewById ... pero probablemente ya lo sepa.
Mi archivo custom_row.xml es RelativeLayout con Button de id "button", TextView de id "text" e ImageView de id "image" - solo para aclarar las cosas.
¡Saludos!

Rampas
fuente
9
Mi solución terminó yendo de otra manera. Resolví el problema estableciendo la propiedad de Focusability descendiente del diseño de fila de la lista para bloquear descendientes y de repente funcionó. Ahora uso un simpleCursorAdapter con un viewbinder personalizado adjunto para realizar la configuración del evento y otras cosas elegantes asociadas con los botones.
CodeFusionMobile
3
Usé esta solución. Sin embargo, una advertencia: si su controlador onClick hace que el contenido de la lista cambie, lo que daría lugar a que se llame a getView Y si su widget tiene estado (como ToggleButton o CheckBox), Y getView establece ese estado, es posible que desee establecer setOnClickListener (nulo) antes de cambiar el estado en onView, para evitar un efecto de bucle.
Pierre-Luc Paour
3
¿qué pasa con mi solución? Tengo la impresión de que es más elegante y se puede aplicar más fácilmente cuando lo necesitemos ..
Ewoks
el primer comentario debe aceptarse como respuesta, por lo que personas como yo no necesitarían horas para encontrarlo
keybee
¡Gracias! Esto fue útil. Me gusta como una alternativa más localizada al enfoque focus: blockDescendants descrito en otros hilos.
Yoav Shapira
18

Cuando un ListView personalizado contiene elementos enfocables, onListItemClick no funcionará (creo que es el comportamiento esperado). Simplemente elimine el enfoque de la vista personalizada, hará el truco:

Por ejemplo:

public class ExtendedCheckBoxListView extends LinearLayout {

    private TextView mText;
    private CheckBox mCheckBox;

    public ExtendedCheckBoxListView(Context context, ExtendedCheckBox aCheckBoxifiedText) {
         super(context);
         
         mText.setFocusable(false);
         mText.setFocusableInTouchMode(false);

         mCheckBox.setFocusable(false);
         mCheckBox.setFocusableInTouchMode(false);
               
    }
}
Rabi
fuente
3
Me gusta su solución: si solo hay un widget en el que se puede hacer clic por fila, negarles la capacidad de enfoque es una solución elegante. Significa que un toque en cualquier parte de la fila coincidirá, pero ese es un comportamiento útil cuando el widget es una radio o una casilla de verificación. Lo mismo se puede lograr en XML usando android: focusable = "false" y android: focusableInTouchMode = "false".
Pierre-Luc Paour
1
la forma xml no parece funcionar si cambia la visibilidad, por lo que uno tiene que hacerlo a través del código después de configurar la "Vista" en visible
max4ever
13

Tengo el mismo problema: ¡OnListItemClick no se activa! [SOLUCIONADO]
Eso sucede en la clase que extiende ListActivity,
con un diseño para ListActivity que el contenido TextBox y ListView anidado en LinearLayout
y otro diseño para las filas (un CheckBox y TextBox anidado en LineraLayout).

Ese es el código:

res / layout / configpage.xml (principal para ListActivity)

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"  
    android:orientation="vertical"  
    android:layout_width="fill_parent"  
    android:layout_height="fill_parent" > 
    <TextView  
        android:id="@+id/selection"  
        android:layout_width="fill_parent"  
        android:layout_height="wrap_content"  
        android:text="pippo" /> 
    <ListView  
        android:id="@android:id/list"  
        android:layout_width="fill_parent"  
        android:layout_height="wrap_content"  
        android:drawSelectorOnTop="false"  
        android:background="#aaFFaa" > 
    </ListView> 
<LinearLayout> 

res/layout/row.xml (layout for single row)  
<LinearLayout  
  xmlns:android="http://schemas.android.com/apk/res/android"  
  android:layout_width="fill_parent"  
  android:layout_height="wrap_content"> 
  <CheckBox  
      android:id="@+id/img"  
      android:layout_width="wrap_content"  
      android:layout_height="wrap_content"  
      **android:focusable="false"**  
      **android:focusableInTouchMode="false"** /> 

  <TextView  
      android:id="@+id/testo"  
      android:layout_width="wrap_content"  
      android:layout_height="wrap_content"  
      **android:focusable="false"**  
      **android:focusableInTouchMode="false"** /> 
</LinearLayout> 

src /.../.../ ConfigPage.java

public class ConfigPage extends ListActivity
{
    TextView selection;

    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.configpage);  
        // loaded from res/value/strings  
        String[] azioni = getResources().getStringArray(R.array.ACTIONS);  
        setListAdapter(new ArrayAdapter&lt;String&gt;(this, R.layout.row, 
                R.id.testo,   azioni));  
        selection = (TextView) findViewById(R.id.selection);  
    }       

    public void onListItemClick(ListView parent, View view, int position, long id)
    {
        selection.setText(" " + position);
    }
}

Esto comienza a funcionar cuando agregué row.xml

  • android:focusable="false"
  • android:focusableInTouchMode="false"

Yo uso Eclipse 3.5.2
Android SDK 10.0.1
min SDK versión: 3

Espero que esto sea útil
... y lo siento por mi inglés :(

rfellons
fuente
@fellons no sé por qué, pero no funcionó para mí. No se está llamando a mi onListItemClick.
likejudo
¿Ha agregado el código de propiedades android: focusable = "false" y android: focusableInTouchMode = código "false"?
rfellons
2

simplemente agregue android:focusable="false"como uno de los atributos de su botón

Juan
fuente
1

Tuve el mismo problema con ToggleButton. Después de medio día de golpearme la cabeza contra una pared, finalmente lo resolví. Es tan simple como hacer que la vista enfocable no sea enfocable, usando 'android: focusable'. También debe evitar jugar con la capacidad de enfoque y la capacidad de hacer clic (acabo de inventar palabras) de la fila de la lista, simplemente déjelas con el valor predeterminado.

Por supuesto, ahora que sus vistas enfocables en la fila de la lista no pueden enfocarse, los usuarios que usan el teclado pueden tener problemas, bueno, enfocarlas. No es probable que sea un problema, pero en caso de que desee escribir aplicaciones 100% impecables, puede usar el evento onItemSelected para hacer que los elementos de la fila seleccionada sean enfocables y los elementos de la fila seleccionada previamente desenfocables.

Ridículo
fuente
Usé este enfoque. Es la forma más sencilla, si puede evitar el problema de no poder concentrarse en elementos individuales. Esto también mantiene los elementos de diseño de estado para los elementos de la lista como deberían ser, lo que no ocurre con algunas de las otras soluciones.
Jonathan S.
1
 ListView lv = getListView();
lv.setTextFilterEnabled(true);

lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
    int position, long id) {
  // When clicked, show a toast with the TextView text
  Toast.makeText(getApplicationContext(), ((TextView) view).getText(),
      Toast.LENGTH_SHORT).show();
}
});
Confucio
fuente
-1

Usé getListAdapter (). GetItem (position) instanciando un objeto que contiene mis valores dentro del elemento

MyPojo myPojo = getListAdapter().getItem(position);

luego usó el método getter de myPojo, llamará a sus valores adecuados dentro del elemento.

Mikey
fuente