Android |获取ViewGroup的所有子元素

时间:2013-09-07 01:56:23

标签: android

getChildAt(i) on只获取ViewGroup的直接子项,是否可以在不进行嵌套循环的情况下访问所有子项?

7 个答案:

答案 0 :(得分:44)

在撰写此答案时,接受的答案存在缺陷,因为它会在结果中包含重复内容。

对于那些在递归时遇到困难的人来说,这是一个非递归的替代方案。你可以获得奖励积分,这也是另一个答案的深度优先方法的广度优先搜索替代方案。

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

一些快速测试(没有正式的)表明这种替代方案也更快,尽管这很可能与另一个答案创建的新ArrayList个实例的数量有关。此外,结果可能会根据视图层次结构的垂直/水平方式而有所不同。

答案 1 :(得分:38)

source

如果你想获得所有子视图以及子ViewGroups中的视图,你必须递归地执行它,因为API中没有提供开箱即用的功能。

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

这将为您提供一个ArrayList,其中包含层次结构中的所有视图,然后您可以迭代它们。

本质上,如果代码在层次结构中找到另一个ViewGroup,则此代码会调用自身,然后返回一个ArrayList以添加到更大的ArrayList中。

答案 2 :(得分:2)

对于使用 androidx kotlin

的用户

1-使用ViewGroup遍历forEach{}

如果要遍历所有childView,则可以在任何ViewGroup中使用预定义的kotlin扩展forEach。示例:

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

2-在.children.toList中使用ViewGroup返回childView列表

要返回Views的列表,可以使用函数children返回Sequence,然后使用toList()将其转换为List。示例:

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

答案 3 :(得分:1)

我以递归的方式重新实现了这个方法。不确定它比MH更快,但至少它没有重复。

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的答案包括给该方法的父视图,所以我创建了这个辅助方法(这是一个被调用的方法)。

我的意思是,如果在TextView(没有子节点)上调用此方法,则返回0而不是1。

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

TLDR:要计算所有孩子的复制和粘贴方法,请调用getAllChildren()

答案 4 :(得分:1)

我不知道它是好还是不。只是覆盖onViewAdded(View子)方法,只需在List<View>中添加视图。通过docs给它想法。这很有用您正在编写自定义视图组

  

将新子项添加到此ViewGroup时调用。覆盖应始终调用super.onViewAdded。

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

}

答案 5 :(得分:1)

我最近遇到了同样的问题,并使用了 Kotlin的扩展功能解决了该问题,

fun ViewGroup.getAllChildren(): List<View> {
    val children = ArrayList<View>()
    for (i in 0 until this.childCount) {
        children.add(this.getChildAt(i))
    }
    return children
}

答案 6 :(得分:0)

这是我的(递归)解决方案,它打印出这样的层次结构:

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