Android |获取视图组的所有子元素

Android |获取视图组的所有子元素,android,Android,getChildAt(i)on仅获取视图组的直接子级,是否可以访问所有子级而不执行嵌套循环?() 如果要获取所有子视图以及子视图组中的视图,必须递归执行,因为API中没有开箱即用的规定 private ArrayList<View> getAllChildren(View v) { if (!(v instanceof ViewGroup)) { ArrayList<View> viewArrayList = new ArrayList<V

getChildAt(i)
on仅获取
视图组的直接子级,是否可以访问所有子级而不执行嵌套循环?

()

如果要获取所有子视图以及子视图组中的视图,必须递归执行,因为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;
}
private ArrayList getAllChildren(视图v){
如果(!(视图组的v实例)){
ArrayList viewArrayList=新建ArrayList();
viewArrayList.add(v);
返回viewArrayList;
}
ArrayList结果=新建ArrayList();
ViewGroup ViewGroup=(ViewGroup)v;
对于(int i=0;i
这将为您提供一个包含层次结构中所有视图的ArrayList,然后您可以对其进行迭代


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

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

对于那些难以理解递归的人,这里有一个非递归的替代方案。如果您意识到这也是一种广度优先的搜索方法,而不是另一个答案的深度优先方法,您将获得额外的分数

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;
}
私有列表getAllChildrenBFS(视图v){ 访问列表=新建ArrayList(); 列表未访问=新建ArrayList(); 未访问。添加(v); 而(!unvisited.isEmpty()){ 查看子项=未访问。删除(0); 访问。添加(儿童); 如果(!(视图组的子实例))继续; ViewGroup group=(ViewGroup)子级; final int childCount=group.getChildCount();
对于(int i=0;i我已经以递归的方式重新实现了这个方法。不确定它是否比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;
    }
}
私有列表GetAllView(视图v){
if(!(v instanceof ViewGroup)| |((ViewGroup)v).getChildCount()==0)//这是一个叶
{List r=new ArrayList();r.add(v);返回r;}
否则{
List List=new ArrayList();List.add(v);//如果是内部节点,则添加自身
int children=((视图组)v.getChildCount();

对于(int i=0;i我不知道它是否好。只需重写onViewAdded(View child)方法,并在
列表中添加视图即可。请思考。由。这在编写自定义视图组时非常有用

将新的子视图添加到此视图组时调用。重写应始终调用super.onViewAdded

下面是我的(递归)解决方案,它按如下方式打印层次结构:

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("  ");
        }
    }
fun ViewGroup.getAllChildren(): List<View> {
    val children = ArrayList<View>()
    for (i in 0 until this.childCount) {
        children.add(this.getChildAt(i))
    }
    return children
}
android.widget.LinearLayout子项:2 id:-1
android.view.view id:21311624246
android.widget.RelativeLayout子项:2 id:21311624247
android.support.v7.widget.AppCompatTextView id:21311624248
android.support.v7.widget.SwitchCompat id:21311624249
公共静态字符串getViewHierarcy(视图组v){
StringBuffer buf=新的StringBuffer();
打印视图(v,buf,0);
返回buf.toString();
}
私有静态字符串打印视图(视图组v、StringBuffer buf、int级别){
final int childCount=v.getChildCount();
v、 getId();
缩进(buf,水平);
追加(v.getClass().getName());
buf.追加(“子项:”);
追加(儿童计数);
buf.append(“id:+v.getId());
buf.追加(“\n”);
for(int i=0;i
我最近遇到了同样的问题,并使用Kotlin的扩展函数解决了它,如下所示:

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("  ");
        }
    }
fun ViewGroup.getAllChildren(): List<View> {
    val children = ArrayList<View>()
    for (i in 0 until this.childCount) {
        children.add(this.getChildAt(i))
    }
    return children
}
fun ViewGroup.getAllChildren():列表{
val children=ArrayList()
for(在0中输入i,直到此.childCount){
添加(this.getChildAt(i))
}
返回儿童
}
适用于使用androidx和kotlin的患者 1-使用
forEach{}
如果要遍历所有子视图,可以在任何视图组中使用预定义的kotlin扩展名
forEach
。例如:

yourViewGroup.forEach{childView->
//对这个childView做些什么
}

2-在
视图组中使用
.children.toList
返回子视图列表 要返回
视图列表
,可以使用函数
子视图
返回
序列
,然后使用
toList()
将其转换为
列表。示例:


val yourChildViewsList:List=yourViewGroup.children.toList()

只要一个
视图组
封装了另一个
视图组
和多个子视图,您的代码就保证在结果集中有重复项。我将让您自己去弄清楚原因。您很接近了,尽管结果中存在所有视图,但它也包含重复项。也许这就是您得到的结果?;)这段代码不会有很多视图组重复吗?因为viewArrayList.add(v)(表示视图组)在每次迭代中都会被调用。比