2010-02-28 10 views
47

ExpandableListView ha un metodo setOnChildClickListener, ma manca di setOnChild Long metodo ClickListener.Android: clic lungo sulle viste secondarie di ExpandableListView?

quando ho aggiunto setOnLongClickListener() in mostra bambino in getChildView(), intero elenco secondario divenne completamente cliccabile (nonostante parentView.setOnChildClickListener() presente e funzionante prima).

Come è possibile abilitare i clic lunghi su viste secondarie?

+0

Vedi dettaglio risposta qui ... http://stackoverflow.com/questions/23646098/android-can-i-use-setonlongclicklistener-and-setonclicklistener-per-same-butto/23646241 # 23646241 – Nepster

risposta

40

ho trovato una risposta sul blog di Steve Oliver qui: http://steveoliverc.wordpress.com/2009/10/16/context-menus-for-expandable-lists/

Si consiglia di utilizzare onCreateContextMenu() invece di cercare setOnChildLongClickListener(). Ecco le informazioni di Steve:

Un elenco espandibile supporta i menu di scelta rapida praticamente nello stesso modo di un elenco standard: aggiungi un listener per il menu di scelta rapida (quando l'utente ha premuto a lungo un elemento di elenco). A differenza di una visualizzazione elenco standard, tuttavia, probabilmente si desidera sapere se l'utente ha selezionato un elemento di gruppo (elemento espandibile) o un elemento secondario (elemento secondario).

Inoltre, non si potrebbe desiderare di fare nulla se l'utente tenta di aprire un menu contestuale su un elemento del gruppo. Potrebbero esserci casi in cui si vorrebbe fare qualcosa a tutti i bambini di un gruppo, ma nella mia applicazione Librarium, volevo ignorare le voci di gruppo e presentare il menu di scelta rapida solo per i bambini.

Innanzitutto, è necessario sapere quando verrà creato il menu di scelta rapida in modo da poter identificare se l'utente ha premuto su un gruppo o un bambino. Se hanno premuto su un gruppo, quindi annullare il menu di scelta rapida. Questo ci dà anche la possibilità di ottenere il testo dell'elemento figlio, in modo che possiamo inserirlo nell'intestazione del menu di scelta rapida.

public void onCreateContextMenu(ContextMenu menu, View v, 
           ContextMenuInfo menuInfo)    
{ 
    super.onCreateContextMenu(menu, v, menuInfo); 

    ExpandableListView.ExpandableListContextMenuInfo info = 
    (ExpandableListView.ExpandableListContextMenuInfo) menuInfo; 

    int type = 
    ExpandableListView.getPackedPositionType(info.packedPosition); 

    int group = 
    ExpandableListView.getPackedPositionGroup(info.packedPosition); 

    int child = 
    ExpandableListView.getPackedPositionChild(info.packedPosition); 

    // Only create a context menu for child items 
    if (type == ExpandableListView.PACKED_POSITION_TYPE_CHILD) 
    { 
    // Array created earlier when we built the expandable list 
    String page =mListStringArray[group][child]; 

    menu.setHeaderTitle(page); 
    menu.add(0, MENU_READ, 0, “Read page”); 
    menu.add(0, MENU_EDIT, 0, “Edit page”); 
    menu.add(0, MENU_FAVORITE, 0, “Add page to favorites”); 
    menu.add(0, MENU_EXPORT, 0, “Export page to file”); 
    menu.add(0, MENU_DELETE, 1, “Delete page”); 
    } 
} 

In secondo luogo, creare il menu contestuale:

public boolean onContextItemSelected(MenuItem menuItem) 
{ 
    ExpandableListContextMenuInfo info = 
    (ExpandableListContextMenuInfo) menuItem.getMenuInfo(); 

    int groupPos = 0, childPos = 0; 

    int type = ExpandableListView.getPackedPositionType(info.packedPosition); 
    if (type == ExpandableListView.PACKED_POSITION_TYPE_CHILD) 
    { 
    groupPos = ExpandableListView.getPackedPositionGroup(info.packedPosition); 
    childPos = ExpandableListView.getPackedPositionChild(info.packedPosition); 
    } 

    // Pull values from the array we built when we created the list 
    String author = mListStringArray[groupPos][0]; 
    String page = mListStringArray[groupPos][childPos * 3 + 1]; 
    rowId = Integer.parseInt(mListStringArray[groupPos][childPos * 3 + 3]); 

    switch (menuItem.getItemId()) 
    { 
    case MENU_READ: 
     readNote(rowId); 
     return true; 

    case MENU_EDIT: 
     editNote(rowId); 
     return true; 

    // etc.. 

    default: 
     return super.onContextItemSelected(menuItem); 
    } 
} 

Questo è tutto. Ora gli utenti possono premere a lungo su un elemento in un elenco espandibile e ottenere il menu di scelta rapida se si tratta di un elemento figlio.

+12

Come nota a margine, non dimenticare la chiamata registerForContextMenu nel metodo onCreate. Se tu (come me) lo dimentichi, allora niente funzionerà. –

+0

Inoltre, non dimenticare di sovrascrivere isChildSelectable per restituire true nell'implementazione di BaseExpandableListAdapter. Senza questo, la vista figli non risponderà ai clic lunghi. –

83

sono riuscito ad ottenere lunghi clic lavorare su un elemento figlio ExpandableListView, utilizzando i seguenti:

getExpandableListView().setOnItemLongClickListener(new OnItemLongClickListener() { 
    @Override 
    public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { 
     if (ExpandableListView.getPackedPositionType(id) == ExpandableListView.PACKED_POSITION_TYPE_CHILD) { 
      int groupPosition = ExpandableListView.getPackedPositionGroup(id); 
      int childPosition = ExpandableListView.getPackedPositionChild(id); 

      // You now have everything that you would as if this was an OnChildClickListener() 
      // Add your logic here. 

      // Return true as we are handling the event. 
      return true; 
     } 

     return false; 
    } 
}); 

Ci sono voluti anni per capire che l'argomento id onItemLongClick è stato l'argomento packedPosition richiesto dalla getPackedPosition * Metodi , certamente non chiaro dalla documentazione.

Nota: Per questa soluzione per funzionare è necessario sovrascrivere le getGroupId e getChildId() metodi nel vostro adattatore

@Override 
    public long getGroupId(int groupPosition) { 
     return groupPosition; 
    } 

    @Override 
    public long getChildId(int groupPosition, int childPosition) { 
     return childPosition; 
    } 
+3

Una soluzione elegante e funzionante. Non è in conflitto con OnChildClickListener. – kaay

+3

Ho seguito questa soluzione e ho riscontrato un problema. Getta outOfIndexException quando ho cercato di ottenere oggetti dall'origine dati della scheda di lista con questi 'childPosition' e' groupPosition'. Ho trovato un'altra risposta qui: http://stackoverflow.com/questions/5806100/identifying-the-group-that-has-been-clicked-in-an-expandablelistview che spiega perché non posso usare id per questo situazione. Finalmente, ho risolto il mio problema con la risposta (la mia risposta è riportata sotto/sopra). – toantran

+0

Questo non ha funzionato per me, il childPosition era sempre 0, quindi ho usato la risposta di autobot_101. – Brandon

1

gestisco ur problema.basta impostare un tag elemento del ur e utilizzarlo, in questo modo:

adapter = new ExpandableListAdapter() { 


     private String[] groups = { "Biceps", "Deltoids", "Hamstrings", "Lower Back","Quadriceps","Triceps","Wrist" }; 
     private String[][] children = { 
       { "Konsantra Dumbell curl", "Hammer curl", "Barbell Biceps Curl", "Prone Curl" }, 
       { "Arnold Press", "Lateral Raise", "Dumbell Upright row", "Bar Military Press" }, 
       { "Dead Lift", "Hack Squat","Zercher Squat","Seated Leg Flexion" }, 
       { "Back Raise", "Superman" }, 
       { "Back Squat", "Bulgarian Split Squat","Dumbell Lunge" }, 
       { "Bench Dip", "French Press","Triceps Extension" }, 
       { "Dumbell Wrist Curl "," Reverse Writst Curl"} 
     }; 
     public void unregisterDataSetObserver(DataSetObserver observer) { 
      // TODO Auto-generated method stub 

     } 

     public void registerDataSetObserver(DataSetObserver observer) { 
      // TODO Auto-generated method stub 

     } 

     public void onGroupExpanded(int groupPosition) { 
      // TODO Auto-generated method stub 

     } 

     public void onGroupCollapsed(int groupPosition) { 
      // TODO Auto-generated method stub 

     } 

     public boolean isEmpty() { 
      // TODO Auto-generated method stub 
      return false; 
     } 

     public boolean isChildSelectable(int groupPosition, int childPosition) { 
      // TODO Auto-generated method stub 
      return true; 
     } 

     public boolean hasStableIds() { 
      // TODO Auto-generated method stub 
      return true; 
     } 

     public View getGroupView(int groupPosition, boolean isExpanded, 
       View convertView, ViewGroup parent) { 
      TextView textView = getGenericView(); 
       textView.setText(getGroup(groupPosition).toString()); 
       textView.setTag((Object)getGroup(groupPosition).toString()+"G"); 
       return textView; 
     } 

     public long getGroupId(int groupPosition) { 
      // TODO Auto-generated method stub 
      return groupPosition; 
     } 

     public int getGroupCount() { 
      // TODO Auto-generated method stub 
      return groups.length; 
     } 

     public Object getGroup(int groupPosition) { 
      // TODO Auto-generated method stub 
      return groups[groupPosition]; 
     } 

     public long getCombinedGroupId(long groupId) { 
      // TODO Auto-generated method stub 
      return 0; 
     } 

     public long getCombinedChildId(long groupId, long childId) { 
      // TODO Auto-generated method stub 
      return 0; 
     } 

     public int getChildrenCount(int groupPosition) { 
      // TODO Auto-generated method stub 
      return children[groupPosition].length; 
     } 

     public View getChildView(int groupPosition, int childPosition, 
       boolean isLastChild, View convertView, ViewGroup parent) { 
      TextView textView = getGenericView(); 
       textView.setText(getChild(groupPosition, childPosition).toString()); 
       textView.setTag((Object)getChild(groupPosition, childPosition).toString()+"C"); 
       return textView; 
     } 

     public long getChildId(int groupPosition, int childPosition) { 
      // TODO Auto-generated method stub 
      return childPosition; 
     } 

     public Object getChild(int groupPosition, int childPosition) { 
      // TODO Auto-generated method stub 
      return children[groupPosition][childPosition]; 
     } 

     public boolean areAllItemsEnabled() { 
      // TODO Auto-generated method stub 
      return false; 
     } 

     public TextView getGenericView() { 
      // Layout parameters for the ExpandableListView 
      AbsListView.LayoutParams lp = new AbsListView.LayoutParams(
        ViewGroup.LayoutParams.FILL_PARENT, 64); 

      TextView textView = new TextView(expandXml.this); 
      textView.setLayoutParams(lp); 
      // Center the text vertically 
      textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT); 
      // Set the text starting position 
      textView.setPadding(36, 0, 0, 0); 

      return textView; 
     } 

    }; 

E poi setOnItemLongClickListener per espandibile ListView.

listView.setOnItemLongClickListener(new OnItemLongClickListener() { 

     public boolean onItemLongClick(AdapterView<?> arg0, View arg1, 
       int arg2, long arg3) { 
      // TODO Auto-generated method stub 
      String s=null; 

       int childPosition =ExpandableListView.getPackedPositionChild(arg3); 
       if(arg1.getTag()!=null){ 
       Object o= arg1.getTag(); 

       s = o.toString(); 
       } 
       Toast.makeText(expandXml.this ,s , Toast.LENGTH_SHORT).show(); 

      return false; 
     } 
    }); 

Eccoci.

+0

Funziona. e salva il mio tempo. – riseres

30

So che questa risposta potrebbe non essere necessaria, ma ho una situazione simile e nessuna di queste risposte risolve il mio problema. Quindi inserisco il mio nel caso qualcuno ne abbia bisogno. Spero che a tutti voi ragazzi non dispiaccia.

@Override 
       public boolean onItemLongClick(AdapterView<?> parent, View childView, int flatPos, long id) { 
        if (ExpandableListView.getPackedPositionType(id) == ExpandableListView.PACKED_POSITION_TYPE_CHILD) { 
          final ExpandableListAdapter adapter = ((ExpandableListView) parent).getExpandableListAdapter(); 
          long packedPos = ((ExpandableListView) parent).getExpandableListPosition(flatPos); 
          int groupPosition = ExpandableListView.getPackedPositionGroup(packedPos); 
          int childPosition = ExpandableListView.getPackedPositionChild(packedPos); 

         // do whatever you want with groupPos and childPos here - I used these to get my object from list adapter. 
        return false; 
       } 

Modifica Questa soluzione per Listview è stato molto tempo fa. Consiglio vivamente di passare a RecyclerView ora.

+2

+1. Questa è la soluzione corretta. È necessario innanzitutto la posizione di visualizzazione piatta (non elaborata), non solo l'ID dell'oggetto in quella posizione. –

+2

wow !!!! Essere d'accordo! Impossibile ottenere childPosition dagli esempi precedenti. Era sempre lo stesso, cioè ZERO - ma ora, quando ho implementato questo codice, sembra funzionare perfettamente !. Farò un voto. –

+2

autobot_101: il mio voto va alla tua risposta. Questa risposta dovrebbe ottenere il massimo dei voti. – MobiDev

12

Ero alla ricerca di questa risposta, ma non qui ha dato risultati corretti.

La risposta contrassegnata da tomash suggerisce un modo completamente diverso. La risposta da Nicholas è parzialmente corretta, ma l'uso di "id" non è corretto.

Corretto, funzionante, la risposta è: convertire il parametro position in packedPosition e THEN! utilizzando questo nuovo valore packedPosition per ottenere il gruppo e l'ID figlio. Controllare il codice qui sotto

getExpandableListView().setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { 

     @Override 
     public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { 
      long packedPosition = getExpandableListView().getExpandableListPosition(position); 
      if (ExpandableListView.getPackedPositionType(packedPosition) == 
        ExpandableListView.PACKED_POSITION_TYPE_CHILD) { 
       // get item ID's 
       int groupPosition = ExpandableListView.getPackedPositionGroup(packedPosition); 
       int childPosition = ExpandableListView.getPackedPositionChild(packedPosition); 

       // handle data 
       ... 

       // return true as we are handling the event. 
       return true; 
      } 
      return false; 
     } 
    }); 

EDIT: ora vedere che autobot ha quasi soluzione corretta, tranne testare getPackedPositionType su id e non su packetPosition

+0

cosa è exListView nella risposta? –

+0

ah scusa, ho migliorato il codice sopra. 'exListView' era l'oggetto' ExpandableListView'. Come quello su cui si imposta questo listener –

+0

Thumbs up per questo. Usare la posizione è meglio che usare id per ottenere packedPosition. –

Problemi correlati