How to easily traverse any view hierarchy in Android

Have you ever wanted to find all the views marked with a specific tag? Well, the Android SDK only allows to find the first one. How about finding a specific type of views?

Faced with this very problem, I had to write a couple of utility classes, and now I’m sharing it the world. Before the library code I’ll show a demonstration of its usage. Here’s how you can traverse the whole view hierarchy of your Activity:

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);

You can pass any ViewGroup instance (such LinearLayout, RelativeLayout and FrameLayout) to the traverse method, and for every view under the hierarchy (including the root ViewGroup itself) the process method will be executed.

If you want to 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);

There are two static methods included which I believe cover the majority of use-cases: 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);

The LayoutTraverser 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);
      }
    }
  }
}

The Views class:

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;
    }
  }
}

Help fellow developers by tweeting or sharing this post!

facebooktwittergoogle_plusreddit

4 thoughts on “How to easily traverse any view hierarchy in Android

    1. admin Post author

      Hello!

      I haven’t applied a licence to it yet. But you are free to use it for any kind of project, open source or commercial. A link to this page in source code would be great, though.

      Good luck!

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>