Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to detect a layout resize?

Dianne Hackborn mentioned in a couple threads that you can detect when a layout as been resized, for example, when the soft keyboard opens or closes. Such a thread is this one... http://groups.google.com/group/android-developers/browse_thread/thread/d318901586313204/2b2c2c7d4bb04e1b

However, I didn't understand her answer: "By your view hierarchy being resized with all of the corresponding layout traversal and callbacks."

Does anyone have a further description or some examples of how to detect this? Which callbacks can I link into in order to detect this?

Thanks

like image 705
cottonBallPaws Avatar asked Nov 13 '10 20:11

cottonBallPaws


5 Answers

One way is View.addOnLayoutChangeListener. There's no need to subclass the view in this case. But you do need API level 11. And the correct calculation of size from bounds (undocumented in the API) can sometimes be a pitfall. Here's a correct example:

view.addOnLayoutChangeListener( new View.OnLayoutChangeListener()
{
    public void onLayoutChange( View v,
      int left,    int top,    int right,    int bottom,
      int leftWas, int topWas, int rightWas, int bottomWas )
    {
        int widthWas = rightWas - leftWas; // Right exclusive, left inclusive
        if( v.getWidth() != widthWas )
        {
            // Width has changed
        }
        int heightWas = bottomWas - topWas; // Bottom exclusive, top inclusive
        if( v.getHeight() != heightWas )
        {
            // Height has changed
        }
    }
});

Another way (as dacwe answers) is to subclass your view and override onSizeChanged.

like image 138
Michael Allan Avatar answered Nov 20 '22 03:11

Michael Allan


Override onSizeChanged in your View!

like image 43
dacwe Avatar answered Nov 20 '22 02:11

dacwe


My solution is to add an invisible tiny dumb view at the end of of the layout / fragment (or add it as a background), thus any change on size of the layout will trigger the layout change event for that view which could be catched up by OnLayoutChangeListener:

Example of adding the dumb view to the end of the layout:

 <View 
    android:id="@+id/theDumbViewId"
    android:layout_width="1dp"
    android:layout_height="1dp"
     />

Listen the event:

    View dumbView = mainView.findViewById(R.id.theDumbViewId);
    dumbView.addOnLayoutChangeListener(new OnLayoutChangeListener() {
        @Override
        public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
            // Your code about size changed
        }
    });
like image 4
Tony Avatar answered Nov 20 '22 04:11

Tony


With Kotlin extensions:

inline fun View?.onSizeChange(crossinline runnable: () -> Unit) = this?.apply {
    addOnLayoutChangeListener { _, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom ->
        val rect = Rect(left, top, right, bottom)
        val oldRect = Rect(oldLeft, oldTop, oldRight, oldBottom)
        if (rect.width() != oldRect.width() || rect.height() != oldRect.height()) {
            runnable();
        }
    }
}

Use thus:

myView.onSizeChange { 
     // Do you thing...
}
like image 4
Slion Avatar answered Nov 20 '22 04:11

Slion


Thank to https://stackoverflow.com/users/2402790/michael-allan this is the good and simple way if you don't want to override all your views. As Api has evolved I would suggest this copy paste instead:

    String TAG="toto";
    ///and last listen for size changed
    YourView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
        @Override
        public void onLayoutChange(View v,
                                   int left, int top, int right, int bottom,
                                   int oldLeft, int oldTop, int oldRight, int oldBottom) {

           boolean widthChanged = (right-left) != (oldRight-oldLeft);
            if( widthChanged )
            {
                // width has changed
                Log.e(TAG,"Width has changed new width is "+(right-left)+"px");
            }
            boolean heightChanged = (bottom-top) != (oldBottom-oldTop);
            if( heightChanged)
            {
                // height has changed
                Log.e(TAG,"height has changed new height is "+(bottom-top)+"px");
            }
        }
    });
like image 1
Mathias Seguy Android2ee Avatar answered Nov 20 '22 03:11

Mathias Seguy Android2ee