Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android | Get all children elements of a ViewGroup

Tags:

android

At the time of writing this answer, the accepted answer is flawed in that it will contains duplicates in its result.

For those who have trouble wrapping their head around recursion, here's a non-recursive alternative. You get bonus points for realizing this is also a breadth-first search alternative to the depth-first approach of the other answer.

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

A couple of quick tests (nothing formal) suggest this alternative is also faster, although that has most likely to do with the number of new ArrayList instances the other answer creates. Also, results may vary based on how vertical/horizontal the view hierarchy is.


(source)

If you want to get all the child views, as well as the views within children ViewGroups, you must do it recursively, since there is no provision in the API to do this out of the 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;
}

This will give you an ArrayList with all the Views in the hierarchy which you can then iterate over.

Essentially, this code call itself if it finds another ViewGroup in the hierarchy, and then returns an ArrayList to be added to the bigger ArrayList.


For those using androidx and kotlin

1 - Iterate through ViewGroup using forEach{}

If you want to iterate through all childViews, you can use predefined kotlin extension forEach in any ViewGroup. Example:

yourViewGroup.forEach{ childView -> // do something with this childView }

2 - Return a list of childViews using .children.toList in a ViewGroup

To return a list of Views, you can use function children to return a Sequence and then use toList() to transform it to a List. Example:

val yourChildViewsList: List<View> = yourViewGroup.children.toList()


I've reimplemented this method in a recursive way. Not sure it's faster than MH's, but at least it has no duplicates.

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's answer includes the parent view which is being given to the method, so I created this auxiliary method (which is the one to be called).

I mean, if you call this method on a TextView (which has no children), it returns 0 instead of 1.

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

TLDR: to count all children copy and paste both methods, call getAllChildren()


I don't know if its good or not.just override the onViewAdded(View child) method and just add the views in List<View>.Give it thoughts.by the docs.This usefull when you are writing custom view group

Called when a new child is added to this ViewGroup. Overrides should always call super.onViewAdded.

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

}