Come attivare su ListItemClick in Listactivity con i pulsanti nell'elenco?


89

Ho un ListActivity semplice che utilizza un ListAdapter personalizzato per generare le visualizzazioni nell'elenco. Normalmente ListAdapter riempirebbe le viste con TextViews, ma ora voglio inserire anche un pulsante lì.

È per mia conoscenza ed esperienza, tuttavia, che l'inserimento di una visualizzazione attivabile nella voce di elenco impedisce l'attivazione di onListItemClick () in ListActivity quando si fa clic sull'elemento di elenco. Il pulsante funziona ancora normalmente all'interno dell'elemento dell'elenco, ma quando viene premuto qualcosa oltre al pulsante, voglio che venga attivato onListItemClick.

Come posso farlo funzionare?


5
la tua soluzione con Focusability discendente è davvero utile, dovresti aggiungerla come risposta e accettarla!
Maksym Gontar

@ Max Il motivo per cui non lo faccio è perché è davvero una cattiva pratica, una soluzione alternativa. Se mai trovassi una soluzione salutare permanente, la risponderei (se ricordo che ho scritto questa domanda un anno fa :))
CodeFusionMobile

Mi piacerebbe anche vedere la soluzione alternativa che hai. Ho provato a impostare il focus discendente e non riesco a farlo funzionare con i pulsanti. Inoltre ho provato a mettere un GridView (con ImageViews in) nella riga dell'elenco e che ha problemi simili.
MrPurpleStreak,

La risposta IMHO che ho dato è una soluzione molto più elegante per il problema rispetto a quella proposta da Ramps e Praveen. PsNon sto cercando di far rivivere la domanda dimenticata qui, ma vedo che non hai ancora accettato alcuna risposta; D
Ewoks

@CodeFusionMobile Potresti accettare la risposta di Ewoks? La risposta con il punteggio più alto è imperfetta perché disabilita l'animazione onclick per l'elemento ListView (dove diventa blu). Risparmierebbe ad altri sviluppatori un po 'di tempo speso a provare la risposta migliore, scoprendo che è imperfetta e quindi andando da Ewoks.
1 ''

Risposte:


99

come ho scritto nel commento precedente, la soluzione è setFocusable (false) su ImageButton.

C'è una soluzione ancora più elegante che prova ad aggiungere android:descendantFocusability="blocksDescendants" nel layout principale dell'elemento della lista. Ciò renderà possibili i clic suListItem e separatamente puoi gestire i clic di Button o ImageButton

Spero che sia d'aiuto ;)

Saluti


3
android:descendantFocusability="blocksDescendants"era perfetto.
Matthew Mitchell

1
tu, amico mio, sei il mio eroe personale. dovresti essere il più votato! questo è molto molto meglio per quasi tutti i casi!
OschtärEi

Questa dovrebbe essere la risposta accettata. Ha funzionato perfettamente per me. Sembra che tutte le visualizzazioni nella voce dell'elenco debbano essere sfocate e questa fa proprio questo senza impostarle singolarmente.
rushinge

1
Questo non sembra funzionare per me. Per layout radice, intendi il layout riga o dove è definito il listview? Comunque ho provato tutte le combinazioni possibili .. non funzionante :(
GreenBee

"Layout radice dell'elemento elenco" come ho scritto .. Supponiamo quindi che tu abbia list e che sia composto da layout (chiamiamoli layout radice dell'elemento lista) che hanno diversi Button, ImageButton, TextVeiw ..
Ewoks

59

Spero di poterti aiutare qui. Presumo che tu abbia un layout personalizzato per gli elementi listView e questo layout è costituito da pulsante e alcune altre visualizzazioni, come TextView, ImageView o altro. Ora vuoi che un evento diverso venga attivato al clic del pulsante e un evento diverso venga attivato su tutto il resto cliccato.

Puoi ottenerlo senza utilizzare onListItemClick () di ListActivity.
Ecco cosa devi fare:

Stai usando un layout personalizzato, quindi probabilmente stai sovrascrivendo il metodo getView () dall'adattatore personalizzato. Il trucco è impostare i diversi ascoltatori per il tuo pulsante e diversi per l'intera vista (la tua riga). Dai un'occhiata all'esempio:

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");
    }
}

La tua classe OnItemClickListener potrebbe essere dichiarata come qui:

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);          
    }       
}

Ovviamente probabilmente aggiungerai altri parametri al costruttore di OnItemClickListener.
E una cosa importante: l'implementazione di getView mostrata sopra è piuttosto brutta, normalmente dovresti usare il pattern ViewHolder per evitare chiamate findViewById .. ma probabilmente lo sai già.
Il mio file custom_row.xml è RelativeLayout con Button of id "button", TextView di id "text" e ImageView di id "image" - solo per rendere le cose chiare.
Saluti!


9
La mia soluzione ha finito per andare in un altro modo. Ho risolto il problema impostando la proprietà Focusability discendente del layout della riga dell'elenco per bloccare i discendenti e improvvisamente ha funzionato. Ora utilizzo un simpleCursorAdapter con un viewbinder personalizzato collegato per eseguire l'impostazione dell'evento e altre cose fantasiose associate ai pulsanti.
CodeFusionMobile

3
Ho usato questa soluzione. Tuttavia, un avviso: se il tuo gestore onClick fa cambiare il contenuto dell'elenco, il che comporterebbe che getView venga chiamato AND se il tuo widget è stateful (come un ToggleButton o CheckBox), E getView imposta quello stato, potresti voler impostareOnClickListener (null) prima di modificare lo stato in onView, per evitare di ottenere un effetto loop.
Pierre-Luc Paour

3
e la mia soluzione? Ho l'impressione che sia più elegante e possa essere applicato più facilmente ogni volta che ne abbiamo bisogno ..
Ewoks

il primo commento dovrebbe essere accettato come risposta, quindi le persone come me non avrebbero bisogno di ore per trovarlo
keybee

Grazie! Questo è stato utile. Mi piace come alternativa più localizzata al focus: approccio blockDescendants descritto in altri thread.
Yoav Shapira

18

Quando un ListView personalizzato contiene elementi attivabili, onListItemClick non funzionerà (penso che sia il comportamento previsto). Basta rimuovere lo stato attivo dalla visualizzazione personalizzata, farà il trucco:

Per esempio:

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);
               
    }
}

3
Mi piace la tua soluzione: se c'è un solo widget "cliccabile" per riga, negare loro la focalizzazione è una soluzione elegante. Significa che un tocco in qualsiasi punto della riga corrisponderà, ma questo è un comportamento utile quando il widget è una radio o una casella di controllo. Lo stesso può essere ottenuto in XML utilizzando android: focusable = "false" e android: focusableInTouchMode = "false".
Pierre-Luc Paour

1
il modo xml non sembra funzionare se si modifica la visibilità, quindi è necessario farlo tramite codice dopo aver impostato "Visualizza" su visibile
max4ever

13

Ho lo stesso problema: OnListItemClick non è stato attivato! [RISOLTO]
Ciò accade su classi che estendono ListActivity,
con un layout per ListActivity che contiene TextBox e ListView annidati in LinearLayout
e un altro layout per le righe (un CheckBox e un TextBox nidificati in LineraLayout).

Questo è il codice:

res / layout / configpage.xml (main per 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);
    }
}

Questo inizia a funzionare quando ho aggiunto row.xml

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

Uso Eclipse 3.5.2
Android SDK 10.0.1
min SDK versione: 3

Spero che questo sia utile
... e mi dispiace per il mio inglese :(


@fellons non so perché, ma non ha funzionato per me. Il mio onListItemClick non viene chiamato.
likejudo

Hai aggiunto il codice proprietà android: focusable = "false" e android: focusableInTouchMode = codice "false"?
rfellons

2

basta aggiungere android:focusable="false"come uno degli attributi del tuo pulsante


1

Ho avuto lo stesso problema con ToggleButton. Dopo mezza giornata passata a sbattere la testa contro un muro ho finalmente risolto il problema. È semplice come rendere la vista focalizzabile non focalizzabile, usando 'android: focusable'. Dovresti anche evitare di giocare con la focalizzazione e la cliccabilità (ho appena composto le parole) della riga dell'elenco, lasciale con il valore predefinito.

Ovviamente, ora che le tue visualizzazioni attivabili nella riga dell'elenco non sono attivabili, gli utenti che utilizzano la tastiera potrebbero avere problemi, beh, focalizzarle. Non è probabile che sia un problema, ma nel caso in cui desideri scrivere app impeccabili al 100%, puoi utilizzare l'evento onItemSelected per rendere gli elementi della riga selezionata attivabili e gli elementi della riga selezionata in precedenza non attivabili.


Ho usato questo approccio. È il modo più semplice, se puoi aggirare il problema di non essere in grado di concentrarti sui singoli elementi. Ciò mantiene anche gli stati disegnabili per gli elementi dell'elenco come dovrebbero essere, cosa che alcune delle altre soluzioni alternative non fanno.
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();
}
});

-1

Ho usato getListAdapter (). GetItem (position) per creare un'istanza di un oggetto che contiene i miei valori all'interno dell'elemento

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

quindi usato il metodo getter da myPojo chiamerà i suoi valori appropriati all'interno dell'elemento.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.