2013-09-07 16 views
23

getChildAt(i) su ottiene solo i figli diretti di un ViewGroup, è possibile accedere a tutti i bambini senza fare cicli nidificati?Android | Ottieni tutti gli elementi figlio di un ViewGroup

+0

http://stackoverflow.com/a/18980154/1093872 sollution molto più ottimale rispetto alle risposte.(Non crea nessun oggetto spazzatura, corre più veloce, più semplice) –

risposta

34

(source)

Se si desidera ottenere tutti i punti di vista del bambino, così come i punti di vista all'interno di figli ViewGroups, devi farlo in modo ricorsivo, dal momento che non v'è nessuna disposizione l'API per farlo fuori dal scatola.

private ArrayList<View> getAllChildren(View v) { 

    if (!(v instanceof ViewGroup)) { 
     ArrayList<View> viewArrayList = new ArrayList<View>(); 
     viewArrayList.add(v); 
     return viewArrayList; 
    } 

    ArrayList<View> result = new ArrayList<View>(); 

    ViewGroup viewGroup = (ViewGroup) v; 
    for (int i = 0; i < viewGroup.getChildCount(); i++) { 

     View child = viewGroup.getChildAt(i); 

     ArrayList<View> viewArrayList = new ArrayList<View>(); 
     viewArrayList.add(v); 
     viewArrayList.addAll(getAllChildren(child)); 

     result.addAll(viewArrayList); 
    } 
    return result; 
} 

Questo vi darà un ArrayList con tutte le viste nella gerarchia che si può poi iterare su.

In sostanza, questo codice si chiama se trova un altro ViewGroup nella gerarchia e quindi restituisce un ArrayList da aggiungere al più grande ArrayList.

+9

Il codice è garantito per avere duplicati nel set di risultati non appena un 'ViewGroup' incapsula un altro' ViewGroup' con più di un figlio. Lascerò a te capire perché. Sei vicino e sebbene tutte le viste siano presenti nel risultato, contiene anche dupes. Forse è quello che ottieni per [copia-incolla] (http://stackoverflow.com/a/11263152/1029225)? ;) –

+0

questo codice non dovrebbe avere molti duplicati di ViewGroup come visualizzazioni ha il ViewGroups? dal momento che viewArrayList.add (v) (che rappresenta il ViewGroup è chiamato in ogni iterazione. – LuisE

40

Al momento della stesura di questa risposta, la risposta accettata è errata in quanto contiene dei duplicati nel suo risultato.

Per coloro che hanno difficoltà a ricucire la testa intorno alla ricorsione, ecco un'alternativa non ricorsiva. Ottieni punti bonus per la realizzazione di questa è anche una alternativa alla ricerca in ampiezza rispetto all'approccio in profondità dell'altra risposta.

private List<View> getAllChildrenBFS(View v) { 
    List<View> visited = new ArrayList<View>(); 
    List<View> unvisited = new ArrayList<View>(); 
    unvisited.add(v); 

    while (!unvisited.isEmpty()) { 
     View child = unvisited.remove(0); 
     visited.add(child); 
     if (!(child instanceof ViewGroup)) continue; 
     ViewGroup group = (ViewGroup) child; 
     final int childCount = group.getChildCount(); 
     for (int i=0; i<childCount; i++) unvisited.add(group.getChildAt(i)); 
    } 

    return visited; 
} 

Un paio di test rapidi (niente di formale) suggeriscono questa alternativa è anche più veloce, anche se questo ha probabilmente a che fare con il numero di nuovi casi ArrayList l'altra risposta crea. Inoltre, i risultati possono variare in base a come verticale/orizzontale è la gerarchia della vista.

+1

Ottima risposta! – breceivemail

1

Ho reimplementato questo metodo in modo ricorsivo. Non sono sicuro che sia più veloce di MH, ma almeno non ha duplicati.

private List<View> getAllViews(View v) { 
    if (!(v instanceof ViewGroup) || ((ViewGroup) v).getChildCount() == 0) // It's a leaf 
     { List<View> r = new ArrayList<View>(); r.add(v); return r; } 
    else { 
     List<View> list = new ArrayList<View>(); list.add(v); // If it's an internal node add itself 
     int children = ((ViewGroup) v).getChildCount(); 
     for (int i=0;i<children;++i) { 
      list.addAll(getAllViews(((ViewGroup) v).getChildAt(i))); 
     } 
     return list; 
    } 
} 

risposta di MH include vista primaria che viene data al metodo, quindi creato questo metodo ausiliario (che è quella di essere chiamato).

Voglio dire, se si chiama questo metodo su un TextView (che non ha figli), restituisce 0 invece di 1.

private List<View> getAllChildren(View v) { 
    List list = getAllViews(v); 
    list.remove(v); 
    return list; 
} 

TLDR: per contare tutti i bambini copiare e incollare entrambi i metodi, chiamare getAllChildren()

1

non so se il suo bene o not.just sovrascrivere il metodo onViewAdded (bambini) e basta aggiungere i punti di vista in List<View> Dialo è thoughts.by l'utile docs .Questo quando si scrive visualizzazione personalizzata gruppo

Chiamato quando un nuovo figlio viene aggiunto a questo ViewGroup. Le sostituzioni devono sempre chiamare super.onViewAdded.

@Override 
public void onViewAdded(View child) { 
    super.onViewAdded(child); 
    views.add(child);//add in list and then use it later 

} 
0

Ecco la mia soluzione (ricorsiva) che stampa il hierarcy in questo modo:

android.widget.LinearLayout children:2 id:-1 
    android.view.View id:2131624246 
    android.widget.RelativeLayout children:2 id:2131624247 
    android.support.v7.widget.AppCompatTextView id:2131624248 
    android.support.v7.widget.SwitchCompat id:2131624249 


public static String getViewHierarcy(ViewGroup v) { 
     StringBuffer buf = new StringBuffer(); 
     printViews(v, buf, 0); 
     return buf.toString(); 
    } 

    private static String printViews(ViewGroup v, StringBuffer buf, int level) { 
     final int childCount = v.getChildCount(); 
     v.getId(); 

     indent(buf, level); 
     buf.append(v.getClass().getName()); 
     buf.append(" children:"); 
     buf.append(childCount); 
     buf.append(" id:"+v.getId()); 
     buf.append("\n"); 

     for (int i = 0; i < childCount; i++) { 
      View child = v.getChildAt(i); 
      if ((child instanceof ViewGroup)) { 
       printViews((ViewGroup) child, buf, level+1); 
      } else { 
       indent(buf, level+1); 
       buf.append(child.getClass().getName()); 
       buf.append(" id:"+child.getId()); 
       buf.append("\n"); 
      } 
     } 
     return buf.toString(); 
    } 

    private static void indent(StringBuffer buf, int level) { 
     for (int i = 0; i < level; i++) { 
      buf.append(" "); 
     } 
    } 
Problemi correlati