Есть ли способ перебрать все виды в вашей деятельности? Что-то вроде:
Iterator it = getViewIterator();
...
Это вообще существует?
Есть ли способ перебрать все виды в вашей деятельности? Что-то вроде:
Iterator it = getViewIterator();
...
Это вообще существует?
Если у вас есть все ваши представления в LinearLayout
или другом container
, который расширяет ViewGroup
, вы можете использовать функции getChildCount()
и getChildAt(int)
и прокручивать все файлы
содержащиеся виды.
Надеюсь, что это поможет.
Предполагая, что под "всеми представлениями в вашей деятельности" вы подразумеваете каждое представление в иерархии, в 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);
Активность Обычно содержит один основной контейнер макетов, в котором размещаются все остальные виды. Использование ссылки Main Layout Container. Пройдите через своего ребенка (используйте getChild (postion), getchildcount() и т.д.). и если какой-либо ребенок является самим контейнером, тогда применяйте к нему ту же функцию. Это похоже на перемещение древовидной структуры
Вот мой пример, основанный на 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;
}
Если вам действительно нужен итератор, в api нет ничего подобного. Вам придется написать свой собственный, который построен поверх логики, предложенной Гарри Джой и Джаванатором.
Если вы хотите избежать уродливости 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 каждый раз, когда выполняете итерацию, но вы можете использовать этот более эффективный алгоритм, если хотите.
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);
}
}
}
Маленькая рекурсивная функция, которая выполняет перечисление всех представлений
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)