buzoherbert buzoherbert - 4 months ago 16
Android Question

Listen to changes in ViewGroup

I have created a very small library to change the fonts of my app.

Up until now I have been changing fonts after inflating layouts and just after adding TextViews to my layouts. It works, but I have to remember to do this for each and every change in my layouts that involves a

TextView
. This is not sustainable for a large project and long term maintenance of my code.

I want a way to listen for changes on the layout from the
Activity
so I can do the font changes there.

I experimented with implementing
ViewGroup.OnHierarchyChangeListener
on my
Activity
like this:

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewGroup viewGroup = (ViewGroup) ((ViewGroup) this
.findViewById(android.R.id.content)).getChildAt(0);
viewGroup.setOnHierarchyChangeListener(this);
}


This seemed to be a great solution because I could listen to
onChildViewAdded(View parent, View child)
and get a reference to whatever
View
was added to my
ViewGroup
. The only problem is that this way to obtain viewGroup doesn't include the ActionBar, but just adding the same listener to the
ActionBar
would suffice.

However,
onChildViewAdded
is never called.

I am doing mostly
Fragment
transactions inside my
Activity
's layout. I don't know if this is what is stopping the callback from happening.

I'm now trying with
ViewTreeObserver.OnDrawListener
, is this the way to go or is there another workaround to listen for changes in a
ViewGroup
?

Answer

The view.setOnHierarchyChangeListener() only gives you callbacks when views are added to this view specifically. When you add views to this view's children, you don't get any callbacks. You will need to listen to them individually.

Look at the code at https://gist.github.com/JakeWharton/7189309:

Whenever a view is added to this, attach a listener to hierarchy changes for all ViewGroup-type children.

This code in the listener demonstrates the idea:

@Override public void onChildViewAdded(View parent, View child) {
    delegate.onChildViewAdded(parent, child);

    if (child instanceof ViewGroup) {
      ViewGroup childGroup = (ViewGroup) child;
      childGroup.setOnHierarchyChangeListener(this);
      for (int i = 0; i < childGroup.getChildCount(); i++) {
        onChildViewAdded(childGroup, childGroup.getChildAt(i));
      }
    }
}