Перечислять/Итерировать все представления в действии?
Есть ли способ перебрать все виды в вашей деятельности? Что-то вроде:
Iterator it = getViewIterator();
...
Это вообще существует?
Ответы
Ответ 1
Если у вас есть все ваши представления в LinearLayout
или другом container
, который расширяет ViewGroup
, вы можете использовать функции getChildCount()
и getChildAt(int)
и прокручивать все файлы
содержащиеся виды.
Надеюсь, что это поможет.
Ответ 2
Предполагая, что под "всеми представлениями в вашей деятельности" вы подразумеваете каждое представление в иерархии, в Android нет такого Iterator
или чего-либо такого, что позволяло бы вам выполнять итерации по всем представлениям.
ViewGroup
имеют методы getChildCount
и getChildAt
, но они о прямых 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
Активность Обычно содержит один основной контейнер макетов, в котором размещаются все остальные виды.
Использование ссылки Main Layout Container. Пройдите через своего ребенка (используйте getChild (postion), getchildcount() и т.д.). и если какой-либо ребенок является самим контейнером, тогда применяйте к нему ту же функцию. Это похоже на перемещение древовидной структуры
Ответ 4
Вот мой пример, основанный на Harry Joy 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;
}
Ответ 5
Если вам действительно нужен итератор, в api нет ничего подобного. Вам придется написать свой собственный, который построен поверх логики, предложенной Гарри Джой и Джаванатором.
Ответ 6
Если вы хотите избежать уродливости for (int я = 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~] )
или если у вас нет/не нужен идентификатор корневого макета
val baseContent = (findViewById<View>(android.R.id.content) as ViewGroup).getChildAt(0) as ViewGroup
processAllViews(baseContent)