如何遍历 Android 视图的所有子视图?

42

我正在为Android制作游戏。为了帮助实现它,我的想法是创建一个视图的子类。然后,我会将几个此类的实例作为主视图的子级插入其中。每个实例都会通过OnTouchListener检测何时被按下。

我现在遇到的问题是如何循环遍历所有这些子视图,以便读取它们的状态并处理它们?(即当它们都达到某种状态时应该发生什么)。

或者,有没有更好的方法可以在屏幕上拥有多个响应触摸且可以检查其状态的对象?

6个回答

70

我已经编写了一个递归函数的小例子:

public void recursiveLoopChildren(ViewGroup parent) {
        for (int i = 0; i < parent.getChildCount(); i++) {
            final View child = parent.getChildAt(i);
            if (child instanceof ViewGroup) {
                recursiveLoopChildren((ViewGroup) child);
                // DO SOMETHING WITH VIEWGROUP, AFTER CHILDREN HAS BEEN LOOPED
            } else {
                if (child != null) {
                    // DO SOMETHING WITH VIEW
                }
            }
        }
    }

该函数将开始循环遍历ViewGroup中的所有视图元素(从第一个到最后一个元素),如果子项是ViewGroup,则重启该函数以检索该子项内的所有嵌套视图。


2
你选择使用 for (int i = parent.getChildCount() - 1; i >= 0; i--) 而不是 for (int i = 0; i < parent.getChildCount(); i++),有什么特别的原因吗? - Peter Prokop
@PeterProkop 我个人更喜欢这个循环。即使在循环期间删除循环中的一个元素,它也能正常工作。 - Sira Lam
@Karacago WebView 是一个 ViewGroup,因此您可以在 if (child instanceof ViewGroup) 之前添加 if (child instanceof WebView) 条件。 - MewX

26

@jqpubliq 是正确的,但如果你真的想要遍历所有视图,你可以简单地使用ViewGroupgetChildCount()getChildAt()方法。一个简单的递归方法就可以完成其余部分。


3

Android如何遍历所有的视图

另一种方法:

public static void recursivelyFindChildren(View view) {
    if (view instanceof ViewGroup) {
        //ViewGroup
        ViewGroup viewGroup = (ViewGroup)view;
        
        for (int i = 0; i < viewGroup.getChildCount(); i++) {
            recursivelyFindChildren(viewGroup.getChildAt(i));
        }

    } else {
        //View
    }

}

最��的回答,或者你可以返回一些可以用于下一步方法的内容。
@Nullable
private static WebView recursivelyFindWebView(View view) {
    if (view instanceof ViewGroup) {
        //ViewGroup
        ViewGroup viewGroup = (ViewGroup)view;

        if (!(viewGroup instanceof WebView)) {
            for (int i = 0; i < viewGroup.getChildCount(); i++) {
                WebView result = recursivelyFindWebView(viewGroup.getChildAt(i));

                if (result != null) {
                    return result;
                }
            }
        } else {
            //WebView

            WebView webView = (WebView)viewGroup;
            return webView;
        }
    }
    return null;
}

2
在Kotlin中,我正在使用ViewGroup的扩展函数:
//call forOneChild for the ViewGroup itself, and all sub Views/ViewGroups
fun ViewGroup.forAllChildren(forOneChild: (v: View) -> Unit) {
    forOneChild(this)
    for (cx in 0 until childCount) {
        val child = getChildAt(cx)
        if (child is ViewGroup)
            child.forAllChildren(forOneChild)
        else
            forOneChild(child)
    }
}

我可以随时从任何地方调用此方法(适用于任何ViewGroup)。
例如:
        //set colors for sub views
        val colorHi = Color.parseColor("#006400") //DarkGreen
        val colorLo = Color.parseColor("#90EE90") //LightGreen

        binding.root.forAllChildren { v ->
            when (v) {
                is CheckBox -> v.buttonTintList = ColorStateList.valueOf(colorHi)
                is Spinner -> v.setPopupBackgroundDrawable(ColorDrawable(colorLo))
            }
        }

1
尝试这个。它获取父布局中的所有视图并返回一个视图列表的数组。
public List<View> getAllViews(ViewGroup layout){
        List<View> views = new ArrayList<>();
        for(int i =0; i< layout.getChildCount(); i++){
            views.add(layout.getChildAt(i));
        }
        return views;
    }

0

使用Views似乎会非常困难,如果有动态效果的话,渲染可能不会很好。除非你正在做一些非常静态的事情,否则你可能想要绘制到Canvas或使用OpenGL。这里有一个来自去年I/O大会的精彩演讲,讲述如何制作Android游戏。它有点长,你可以跳过前15分钟。此外,源代码也是可用的。这应该能给你提供一些关于如何处理事情的好主意。


是的,我可能需要用不同的方式来做,但我会先尝试这个。这是一个休闲游戏。 - Slapout

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接