Enumerate/Iterate all Views in Activity?
Is there a way to iterate through 开发者_Python百科all the views in your Activity? Something like:
Iterator it = getViewIterator();
...
Does this exist at all?
If you have all your Views in a LinearLayout
or an other container
that extends ViewGroup
you can use the functions getChildCount()
and getChildAt(int)
and iterate through all of the
contained views.
Hope this helps.
Assuming by "all the views in your Activity" you mean every view in the hierarchy, there's no such Iterator
or anything in Android that allows you iterate over all views.
ViewGroup
s have getChildCount
and getChildAt
methods, but they are about direct children of the ViewGroup
. So, you would need to visit every child, and check if it's a ViewGroup
itself, and so on. Long story short, I wanted such a functionality to find all views that match a specific tag (findViewWithTag only returns the first). Here is a class which can iterate all views:
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;
}
}
Use it like this:
LayoutTraverser.build(new LayoutTraverser.Processor() {
@Override
public void process(View view) {
// do stuff with the view
}
}).traverse(viewGroup);
Here is my example, based on Harry Joy's answer. It iterates through all hierarchies of the parent ViewGroup
to see if any of the views anywhere within it are a 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;
}
Activity Generally contains one main Layout Container in which all other views are placed. Using the reference of Main Layout Container. Traverse through its child (Use getChild(postion) , getchildcount() etc). and if any child is a container itself then apply the same function on it..This is some like traversing a tree structure
If you actually need an iterator, there isn't anything like that available in the api. You'll have to write your own that is built on top of the logic that Harry Joy and Javanator suggest.
If you want to avoid the ugly for (int i = 0; ....) you can use a static wrapper
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);
}
};
}
};
}
}
and use it like so
for (View view : Tools.getChildViews(viewGroup))
of course this is slightly less efficient since you are creating a new Iteratable object every time you iterate, but you could build on this a more efficient algo if you want.
Rx java solution
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);
}
}
}
Small recursive function which does enumerating all views
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
}
}
}
Written in Kotlin.
To use this function:
processAllViews( [~rootLayoutId~] )
or if you don't have / don't want root layout id
val baseContent = (findViewById<View>(android.R.id.content) as ViewGroup).getChildAt(0) as ViewGroup
processAllViews(baseContent)
精彩评论