getChildAt(i)
on只获取ViewGroup
的直接子项,是否可以在不进行嵌套循环的情况下访问所有子项?
答案 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)
ViewGroup
遍历forEach{}
如果要遍历所有childView,则可以在任何ViewGroup中使用预定义的kotlin扩展forEach
。示例:
yourViewGroup.forEach{ childView ->
// do something with this childView
}
.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(" ");
}
}