getChildAt(i)
on получает только прямые дочерние элементы ViewGroup
, возможно ли получить доступ ко всем дочерним элементам без выполнения вложенных циклов?
Android | Получить все дочерние элементы группы ViewGroup
Ответ 1
(источник)
Если вы хотите получить все дочерние представления, а также представления в дочерних элементах 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
Во время написания этого ответа принятый ответ ошибочен тем, что он будет содержать дубликаты в своем результате.
Для тех, у кого есть проблемы, обертывание головы вокруг рекурсии, здесь нерекурсивная альтернатива. Вы получаете бонусные баллы за то, что понимаете, что это также альтернативный вариант поиска в глубину первого варианта ответа.
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
, которые создает другой ответ. Кроме того, результаты могут варьироваться в зависимости от вертикальной/горизонтальной иерархии представлений.
Ответ 3
Я повторил этот метод рекурсивным образом. Не уверен, что это быстрее, чем MH, но по крайней мере у него нет дубликатов.
private List<View> getAllViews(View v) {
if (!(v instanceof ViewGroup) || ((ViewGroup) v).getChildCount() == 0) // It 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 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;
}
TL;DR: чтобы подсчитать всех детей, скопируйте и вставьте оба метода, вызовите getAllChildren()
Ответ 4
Я не знаю, хорошо ли это или нет. Просто переопределите метод onViewAdded (View child) и просто добавьте представления в 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
Вот мое (рекурсивное) решение, которое печатает иерархию следующим образом:
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(" ");
}
}