draco1023
12/17/2013 - 3:16 AM

A way to easily traverse any view hierarchy in Android

A way to easily traverse any view hierarchy in Android

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;
    }
  }
}
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);
      }
    }
  }
}
/* 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);