【问题标题】:Android - get children inside a View?Android - 在视图中获取孩子?
【发布时间】:2012-01-13 18:36:05
【问题描述】:

给定一个视图,我如何才能在其中获取子视图?

所以我有一个自定义视图,调试器显示在mChildren 下还有 7 个其他视图。 我需要一种访问这些视图的方法,但似乎没有公共 API 可以执行此操作。

有什么建议吗?

编辑:

我的自定义视图继承自 AdapterView

【问题讨论】:

    标签: android view


    【解决方案1】:
    for(int index = 0; index < ((ViewGroup) viewGroup).getChildCount(); index++) {
        View nextChild = ((ViewGroup) viewGroup).getChildAt(index);
    }
    

    这样可以吗?

    【讨论】:

    • 递归执行此操作从而生成视图层次结构 JSON 对象的最佳方法是什么?
    • 假设父View被命名为viewGroup
    【解决方案2】:

    如果你不仅想得到所有的直接孩子,还想得到所有孩子的孩子等等,你必须递归地做:

    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 vg = (ViewGroup) v;
        for (int i = 0; i < vg.getChildCount(); i++) {
    
            View child = vg.getChildAt(i);
    
            ArrayList<View> viewArrayList = new ArrayList<View>();
            viewArrayList.add(v);
            viewArrayList.addAll(getAllChildren(child));
    
            result.addAll(viewArrayList);
        }
        return result;
    }
    

    要使用结果,您可以执行以下操作:

        // check if a child is set to a specific String
        View myTopView;
        String toSearchFor = "Search me";
        boolean found = false;
        ArrayList<View> allViewsWithinMyTopView = getAllChildren(myTopView);
        for (View child : allViewsWithinMyTopView) {
            if (child instanceof TextView) {
                TextView childTextView = (TextView) child;
                if (TextUtils.equals(childTextView.getText().toString(), toSearchFor)) {
                    found = true;
                }
            }
        }
        if (!found) {
            fail("Text '" + toSearchFor + "' not found within TopView");
        }
    

    【讨论】:

    • 此调用不保存,例如child 可以是 View 类型而不是 ViewGroup,因此 getAllChildren 的递归调用可能会导致异常,因为强制转换失败。所以你应该添加一个 if (!(v instanceof ViewGroup)) return;演员前
    • 小建议:用for (int i = 0, n = vg.getChildCount(); i &lt; n; i++) 替换你的for循环 在Android上,访问局部变量而不是调用方法往往要快得多。这样,每个视图组只调用一次方法,然后在后续运行中使用局部变量。
    • 因为 Phil Diegmann 的建议,我更改了代码。希望这可以帮助。为我工作。
    • 酷。我只建议添加一个布尔值'includeViewGroups',并且只有当它为真时,iewArrayList.add(v);这对于在适配器中进行迭代很有用(我只需要叶子)。谢谢!
    【解决方案3】:

    您始终可以通过 View.findViewById() http://developer.android.com/reference/android/view/View.html#findViewById(int) 访问子视图。

    例如,在一个活动/视图中:

    ...
    private void init() {
      View child1 = findViewById(R.id.child1);
    }
    ...
    

    或者如果你有一个视图的引用:

    ...
    private void init(View root) {
      View child2 = root.findViewById(R.id.child2);
    }
    

    【讨论】:

    • 我无法访问 id,UI 是通过代码生成的,我正在使用 robotsium 编写自动化,所以我能做的事情是有限的
    • @jonson,如果你需要得到所有孩子,那根本没用。
    【解决方案4】:

    我将提供此答案作为@IHeartAndroid 的递归算法的替代方案,用于发现视图层次结构中的所有子Views。请注意,在撰写本文时,递归解决方案存在缺陷,因为它的结果中会包含重复项。

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

    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 实例的数量有关。此外,结果可能会根据视图层次结构的垂直/水平程度而有所不同。

    交叉发帖人:Android | Get all children elements of a ViewGroup

    【讨论】:

      【解决方案5】:

      这里有一个建议:您可以获取由R 使用其给定名称(例如My Str)生成的ID(例如由android:id="@+id/..My Str.. 指定)。使用getIdentifier() 方法的代码 sn-p 将是:

      public int getIdAssignedByR(Context pContext, String pIdString)
      {
          // Get the Context's Resources and Package Name
          Resources resources = pContext.getResources();
          String packageName  = pContext.getPackageName();
      
          // Determine the result and return it
          int result = resources.getIdentifier(pIdString, "id", packageName);
          return result;
      }
      

      Activity 中,与findViewById 结合使用的示例用法如下:

      // Get the View (e.g. a TextView) which has the Layout ID of "UserInput"
      int rID = getIdAssignedByR(this, "UserInput")
      TextView userTextView = (TextView) findViewById(rID);
      

      【讨论】:

        【解决方案6】:

        作为 2018 年后遇到此问题的更新,如果您使用的是 Kotlin,您可以简单地使用 Android KTX 扩展属性 ViewGroup.children 来获取 View 的直接子级序列。

        【讨论】:

          【解决方案7】:

          此方法采用布局内的所有视图,这类似于 Alexander Kulyakhtin 的回答。不同之处在于,它接受任何类型的父布局并返回视图数组列表。

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

          【讨论】:

            【解决方案8】:

            为了刷新表格布局(TableLayout),我最终不得不使用上面提到的递归方法来获取所有孩子的孩子等等。

            我的情况有些简化,因为我只需要使用 LinearLayout 以及从它扩展的那些类,例如 TableLayout。而且我只对寻找 TextView 孩子感兴趣。但我认为它仍然适用于这个问题。

            最后一个类作为一个单独的线程运行,这意味着它可以在为孩子解析之前在后台做其他事情。代码小而简单,可以在github上找到:https://github.com/jkincali/Android-LinearLayout-Parser

            【讨论】:

              猜你喜欢
              • 2015-03-17
              • 1970-01-01
              • 1970-01-01
              • 2012-07-18
              • 2018-03-12
              • 1970-01-01
              • 2023-03-25
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多