John W
John W

Reputation: 610

How to force a redraw of the views in Activity.onConfigurationChanged

I've got three views in my activity in a linear vertical layout. The top and bottom views have fixed heights and the middle view takes whatever height is left available. This is how I set the sizes for the views:

void resize(int clientHeight)
{
    int heightMiddle = clientHeight - heightTop - heightBottom;
    topView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, heightTop));
    middleView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, heightMiddle));
    bottomView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT));
}

In order to obtain the clientHeight, I overrode the onMeasure() function and call resize() inside my overridden onMeasure() function. This works well in onCreate(). However when the phone orientation changes, it does not work. What I observed is that after onCreate(), onMeasure() is called twice. After onConfigurationChanged(), onMeasure() is only called once and my resizing code does not get a chance to take effect. My kluge solution is to setup a timer to call resize() 20ms later:

timer.schedule(new TimerTask()
{
    @Override
    public void run()
    {
        activity.runOnUiThread(new UiTask());
    }
}, 20);

where UiTask will simply call resize(). This works for me, but I feel that there's got to be a better solution. Can someone shed some light on this?

Upvotes: 0

Views: 1878

Answers (1)

Martin Nordholts
Martin Nordholts

Reputation: 10358

Why not let LinearLayout do the layouting with the help of the android:layout_weight attribute? That way, you don't need any extra code at all, everything will just work. Here's what your res/layout/main.xml could look like:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
    <TextView
        android:layout_width="match_parent" 
        android:layout_height="50dp"
        android:text="Top"
        android:layout_weight="0" 
        android:background="#ff0000"
        />
    <TextView  
        android:layout_width="match_parent" 
        android:layout_height="match_parent"
        android:text="Middle"
        android:layout_weight="1" 
        android:background="#00ff00"
        />
    <TextView  
        android:layout_width="match_parent" 
        android:layout_height="25dp"
        android:text="Bottom"
        android:layout_weight="0" 
        android:background="#0000ff"
        />
</LinearLayout>

And with no more code other than the regular

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
}

it would look like this in portrait:

enter image description here

and like this in landscape (automatically relayouted and redrawn):

enter image description here

This works both with and without android:configChanges="orientation" for the activity in the manifest. You'll also be able to setup the above layout using Java code if you need to.

Upvotes: 1

Related Questions