2013-09-07 9 views
23

getChildAt(i) auf erhält nur die direkten Kinder von ViewGroup, ist es möglich, auf alle Kinder zuzugreifen, ohne geschachtelte Schleifen zu tun?Android | Erhalten Sie alle Kinder Elemente einer ViewGroup

+0

http://stackoverflow.com/a/18980154/1093872 weit optimaleren sollution als die Antworten.(Erzeugt keinen Objektmüll, läuft schneller, einfacher) –

Antwort

34

(source)

Wenn Sie alle untergeordneten Ansichten erhalten möchten, sowie die Ansichten innerhalb Kinder ViewGroups, müssen Sie es rekursiv tun, da es keine Bestimmung in der API ist dies aus der tun Box.

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

Dadurch werden Sie in der Hierarchie eine Arraylist mit allen Ansichten geben, die Sie dann über laufen kann.

Im Wesentlichen ruft dieser Code sich selbst auf, wenn er eine andere ViewGroup in der Hierarchie findet, und gibt dann eine ArrayList zurück, die zur größeren ArrayList hinzugefügt wird.

+9

Ihr Code ist garantiert Duplikate in der Ergebnismenge, sobald eine 'ViewGroup' eine andere' ViewGroup' mit mehr als einem Kind einkapselt. Ich werde es dir überlassen, um herauszufinden, warum. Sie sind nah, und obwohl alle Ansichten im Ergebnis vorhanden sind, enthält es auch Duples. Vielleicht bekommst du das für [Kopieren-Einfügen] (http://stackoverflow.com/a/11263152/1029225)? ;) –

+0

hätte dieser Code nicht viele ViewGroup-Duplikate, wie Views die ViewGroups? seit viewArrayList.add (v) (das die ViewGroup darstellt, wird in jeder Iteration aufgerufen. – LuisE

40

Zum Zeitpunkt der Erstellung dieser Antwort ist die akzeptierte Antwort insofern fehlerhaft, als sie Duplikate in ihrem Ergebnis enthält.

Für diejenigen, die Schwierigkeiten haben, ihren Kopf rund um Rekursion zu wickeln, hier ist eine nicht-rekursive Alternative. Sie erhalten Bonuspunkte, um zu erkennen, dass dies auch eine breitere Suche als Alternative zum Tiefenansatz der anderen Antwort ist.

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

Ein paar schnelle Tests (nichts formal) deuten darauf hin, diese Alternative auch schneller ist, aber das hat höchstwahrscheinlich mit der Anzahl der neuen ArrayList Instanzen zu tun, die andere Antwort erzeugt. Außerdem können die Ergebnisse abhängig davon variieren, wie vertikal/horizontal die Ansichtshierarchie ist.

+1

Ausgezeichnete Antwort! – breceivemail

1

Ich habe diese Methode rekursiv re-implementiert. Nicht sicher, es ist schneller als MH, aber es hat zumindest keine Duplikate.

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

MH Antwort enthält die übergeordnete Ansicht, die das Verfahren gegeben wird, so habe ich diese Hilfsmethode (die der einer aufgerufen werden soll).

Ich meine, wenn Sie auf einem Textview diese Methode aufrufen (die keine Kinder hat), gibt es 0 statt 1.

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

TLDR: zählen alle Kinder kopieren und beide Methoden einfügen, rufen getAllChildren()

1

ich weiß nicht, ob seine guten oder not.just überschreiben die onViewAdded (Kinder) Methode und fügen Sie einfach die Ansichten in List<View> .Give es thoughts.by der docs .Dieses nützlich, wenn Sie benutzerdefinierte Ansicht schreiben Gruppe

Wird aufgerufen, wenn dieser ViewGroup ein neues Kind hinzugefügt wird. Überschreibungen sollten immer super.onViewAdded aufrufen.

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

} 
0

Hier ist meine (rekursiv) Lösung, die die hierarcy wie folgt ausgibt:

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