【问题标题】:Enumerate/Iterate all Views in Activity?枚举/迭代活动中的所有视图?
【发布时间】:2011-06-19 19:47:02
【问题描述】:

有没有办法遍历 Activity 中的所有视图?比如:

Iterator it = getViewIterator();
...

这真的存在吗?

【问题讨论】:

  • 我想知道,你为什么想要那个?
  • 是的,这样做有什么要求..?
  • code.google.com/p/android/issues/detail?id=8488,我的代码接近底部
  • 您可能想要将自定义字体应用于所有文本字段...这就是我到达这里的方式;)
  • 我需要做同样的事情,但在我的应用程序之外,即;在另一个应用程序/jar 中运行.. 是否有可能以及如何?

标签: android iterator


【解决方案1】:

如果您在 LinearLayout 或扩展 ViewGroup 的其他 container 中拥有所有视图,则可以使用函数 getChildCount()getChildAt(int) 并遍历所有
包含视图。

希望这会有所帮助。

【讨论】:

  • 是的,这非常有效。谢谢!我必须在我的基本活动中覆盖我的 setContentView() 函数,以便我可以存储一个指向根 ViewGroup 的指针,然后通过你的方法对其进行迭代。
  • 替代覆盖 setContentView,您可以为正在膨胀的视图中最外层的容器提供一个 ID,然后使用 findViewById() 获取它。
【解决方案2】:

假设“您的 ​​Activity 中的所有视图”是指层次结构中的每个视图,那么在 Android 中没有这样的 Iterator 或任何允许您遍历所有视图的东西。

ViewGroups 有 getChildCountgetChildAt 方法,但它们是 ViewGroup 的直接子代。因此,您需要访问每个孩子,并检查它是否是 ViewGroup 本身,等等。长话短说,我想要这样一个功能来查找与特定标签匹配的所有视图(findViewWithTag 只返回第一个)。这是一个可以迭代所有视图的类:

public class LayoutTraverser {

    private final Processor processor;


    public interface Processor {
        void process(View view);
    }

    private LayoutTraverser(Processor processor) {
        this.processor = processor;
    }

    public static LayoutTraverser build(Processor processor) {
        return new LayoutTraverser(processor);
    }

    public View traverse(ViewGroup root) {
        final int childCount = root.getChildCount();

        for (int i = 0; i < childCount; ++i) {
            final View child = root.getChildAt(i);

            if (child instanceof ViewGroup) {
                traverse((ViewGroup) child);
            }
        }
        return null;
    }
}

像这样使用它:

LayoutTraverser.build(new LayoutTraverser.Processor() {
  @Override
  public void process(View view) {
    // do stuff with the view
  }
}).traverse(viewGroup);

【讨论】:

【解决方案3】:

这是我的示例,基于Harry Joy's answer。它遍历父 ViewGroup 的所有层次结构,以查看其中任何位置的任何视图是否是 Button

private boolean doesViewGroupContainButton(ViewGroup parentView) {

        int numChildViews = parentView.getChildCount();
        for (int i = 0; i < numChildViews; i++) {
            View childView = parentView.getChildAt(i);
            if (childView instanceof ViewGroup) {
                if (doesViewContainButton((ViewGroup)childView)) {
                    return true;
                }
            }
            else if (childView instanceof Button) {
                return true;
            }
        }
        return false;

    }

【讨论】:

    【解决方案4】:

    Activity 通常包含一个主布局容器,所有其他视图都放置在其中。 使用 Main Layout Container 的参考。遍历其子节点(使用 getChild(postion) 、 getchildcount() 等)。如果任何孩子本身就是一个容器,则对其应用相同的功能..这有点像遍历树结构

    【讨论】:

      【解决方案5】:

      如果您确实需要一个迭代器,那么 api 中没有类似的东西可用。您必须根据 Harry Joy 和 Javanator 建议的逻辑编写自己的代码。

      【讨论】:

        【解决方案6】:

        如果你想避免丑陋的 for (int i = 0; ....) 你可以使用静态包装器

        public class Tools
        {
            public static Iterable<View> getChildViews(final ViewGroup view)
            {
                return new Iterable<View>()
                {
                    int i = -1;
        
                    @NonNull
                    @Override
                    public Iterator<View> iterator()
                    {
                        return new Iterator<View>()
                        {
                            int i = -1;
                            @Override
                            public boolean hasNext()
                            {
                                return i < view.getChildCount();
                            }
        
                            @Override
                            public View next()
                            {
                                return view.getChildAt(++i);
                            }
                        };
                    }
        
                };
            }
        }
        

        并像这样使用它

        for (View view :  Tools.getChildViews(viewGroup))
        

        当然,这会稍微降低效率,因为您每次迭代时都会创建一个新的 Iteratable 对象,但如果您愿意,您可以在此基础上构建一个更高效的算法。

        【讨论】:

          【解决方案7】:

          Rx java解决方案

              public static Observable<View> iterate(@NonNull View root) {
                  return Observable.create(emitter -> {
                      iterate(root, emitter);
                      emitter.onComplete();
                  });
              }
          
              private static void iterate(@NonNull View view, @NonNull ObservableEmitter<View> emitter) {
                  emitter.onNext(view);
                  if (view instanceof ViewGroup) {
                      ViewGroup viewGroup = (ViewGroup) view;
                      for (int i = 0; i < viewGroup.getChildCount(); i++) {
                          iterate(viewGroup.getChildAt(i), emitter);
                      }
                  }
              }
          

          【讨论】:

            【解决方案8】:

            枚举所有视图的小递归函数

             private fun processAllViews(viewGroup: ViewGroup) {
                for (child in viewGroup.children) {
                    if (child is EditText) {
                       // do some stuff with EditText
                    } else if (child !is ViewGroup) {
                        // do some stuff with not EditText and not ViewGroup
                    } else {
                        processAllViews(child as ViewGroup) // process inner layout
                    }
                }
            }
            

            用 Kotlin 编写。

            要使用这个功能:

            processAllViews( [~rootLayoutId~] )
            

            或者如果您没有/不想要根布局 ID

            val baseContent = (findViewById<View>(android.R.id.content) as ViewGroup).getChildAt(0) as ViewGroup
            processAllViews(baseContent)
            

            【讨论】:

              猜你喜欢
              • 2021-12-18
              • 2011-05-13
              • 2011-02-07
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-10-06
              相关资源
              最近更新 更多