Skip to content

Instantly share code, notes, and snippets.

@gelitenight
Last active November 8, 2023 08:42
Show Gist options
  • Star 20 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save gelitenight/7999448 to your computer and use it in GitHub Desktop.
Save gelitenight/7999448 to your computer and use it in GitHub Desktop.
A way to easily traverse any view hierarchy in Android
/* basic usage */
ViewGroup root = (ViewGroup) findViewById(android.R.id.content);
LayoutTraverser.build(new LayoutTraverser.Processor() {
@Override
public void process(View view) {
// do stuff with the view
}
}).traverse(root);
/* traverse multiple hierarchies using the same processing logic */
LayoutTraverser traverser = LayoutTraverser.build(new LayoutTraverser.Processor() {
@Override
public void process(View view) {
// do stuff with the view
}
});
traverser.traverse(root);
traverser.traverse(root2);
traverser.traverse(root3);
/* two static methods: finding views by tag and finding views of a specific type */
// all views tagged "coolView" under "root"
List<View> coolViews = Views.find(root, "coolView");
// all ImageView views under "root"
List<ImageView> imageViews = Views.find(root, ImageView.class);
package com.androidwtf.android;
import android.view.View;
import android.view.ViewGroup;
public class LayoutTraverser {
public interface Processor {
void process(View view);
}
private final Processor processor;
private LayoutTraverser(Processor processor) {
this.processor = processor;
}
public static LayoutTraverser build(Processor processor) {
return new LayoutTraverser(processor);
}
public void traverse(ViewGroup root) {
final int childCount = root.getChildCount();
for (int i = 0; i < childCount; ++i) {
final View child = root.getChildAt(i);
processor.process(child);
if (child instanceof ViewGroup) {
traverse((ViewGroup) child);
}
}
}
}
package com.androidwtf.android;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.List;
final public class Views {
private Views() {}
public static List<View> find(ViewGroup root, Object tag) {
FinderByTag finderByTag = new FinderByTag(tag);
LayoutTraverser.build(finderByTag).traverse(root);
return finderByTag.getViews();
}
public static <T extends View> List<T> find(ViewGroup root, Class<T> type) {
FinderByType<T> finderByType = new FinderByType<T>(type);
LayoutTraverser.build(finderByType).traverse(root);
return finderByType.getViews();
}
private static class FinderByTag implements LayoutTraverser.Processor {
private final Object searchTag;
private final List<View> views = new ArrayList<View>();
private FinderByTag(Object searchTag) {
this.searchTag = searchTag;
}
@Override
public void process(View view) {
Object viewTag = view.getTag();
if (viewTag != null && viewTag.equals(searchTag)) {
views.add(view);
}
}
private List<View> getViews() {
return views;
}
}
private static class FinderByType<T extends View> implements LayoutTraverser.Processor {
private final Class<T> type;
private final List<T> views;
private FinderByType(Class<T> type) {
this.type = type;
views = new ArrayList<T>();
}
@Override
@SuppressWarnings("unchecked")
public void process(View view) {
if (type.isInstance(view)) {
views.add((T) view);
}
}
public List<T> getViews() {
return views;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment