1

I need to build a layout that fills the screen. I do that using a LinearLayout with weights in their child views.

This layout is a form, so I also need it to be scrollable when the soft keyboard is out.

What happens is that the screen height is shrunk when the keyboard is out, so the views are shrunk too, crowded together. They look awful.

Do you know any way to build a form layout that fills the screen but at the same time preserves its aspect and can be scrollable when the soft keyboard is out? This is really easy in iOS but in Android... I can't think of a solution.

Thank you

Ferran Maylinch
  • 10,919
  • 16
  • 85
  • 100

4 Answers4

1

iOS always has the same screensize, Android doesnt. You need to use a responsive design in Android since you dont know how big the screen is that the user is using.

I dont think you need weights(not verticle anyway) to fix this. Just use a ScrollView and add a LinearLayout(orientation:vertical) inside it. Add your views inside this LinearLayout, and if you need to have multiple views horizontally. Add another LinearLayout(orientation:horizontal) Set margin on your views to get a nice distance between them.

This will allow users that have small screens to scroll in your layout, and if the user has the keyboard out they can scroll aswell.

<ScrollView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" >

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="15dp"
            android:layout_marginRight="15dp"
            android:orientation="vertical" >

            <TextView
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"/>

            <TextView
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"/>

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal" >

            <TextView
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"/>

            <TextView
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"/>
            </LinearLayout>

        </LinearLayout>
    </ScrollView>

The first two will lie beneath each other. The next two will lie next to each other, apply weights here if you want them to be of different sizes

Joakim Palmkvist
  • 540
  • 2
  • 11
  • Thanks Joakim, but I want my form to take all the screen. Not half of the screen on large devices and more than a screen on small ones. That's why I use weights: to fill the screen while being responsive. I think the problem is screen height is altered when the soft keyboard is out. – Ferran Maylinch Mar 20 '14 at 14:37
  • 1
    In that case, I think you should go with doing it programmaticly. You can measure the height of the window and set the heights of your views accordingly. – Joakim Palmkvist Mar 20 '14 at 15:00
  • That's almost exactly what I thought, thanks. I measure the height of the `LinearLayout` that contains the weighted views and transform the relative heights to absolute heights. I'll post the answer when I refine it. – Ferran Maylinch Mar 20 '14 at 15:41
  • 1
    Check out this thread for the ViewTreeObserver: http://stackoverflow.com/questions/3779173/determining-the-size-of-an-android-view-at-runtime – Joakim Palmkvist Mar 20 '14 at 15:53
  • Thanks! I'm using `onWindowFocusChanged` as a "callback" where the measures are set. Is the ViewTreeObserver a better solution? – Ferran Maylinch Mar 20 '14 at 16:02
  • Thanks again, Joakim. I was using `onWindowFocusChanged` but `ViewTreeObserver` fits better in my solution. – Ferran Maylinch Mar 20 '14 at 18:10
0

Define your form within scroll view and in manifest make the windowSoftInputMode, configChanges entries as shown below

    <activity
        android:name="com.example.MainActivity"
        android:label="@string/app_name" 
        android:screenOrientation="portrait" 
        android:windowSoftInputMode="stateAlwaysHidden|adjustResize"           
        android:configChanges="keyboardHidden|orientation">

</activity>

Hopefully this can help you.

InnocentKiller
  • 5,234
  • 7
  • 36
  • 84
Ajit
  • 724
  • 7
  • 16
  • Thanks but that doesn't work as I expect. If I use relative heights (with weights) the views look smaller and appear closer to each other when the keyboard is out. That's because the screen height is reduced. – Ferran Maylinch Mar 20 '14 at 14:39
0

I have built the following scheduleConsolideHeights method to solve the problem. Thanks to Joakim for his comments.

Although it works fine for me, I'm sure it can be improved. Any suggestion will be welcome.

public class MyActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.XXX);

        // LinearLayout from your R.layout.XXX that has vertical orientation and
        // its children have weights instead of absolute heights
        final LinearLayout layout = (LinearLayout) findViewById(R.id.layout_with_weights);

        scheduleConsolideHeights(layout);
    }

    /**
     * Adds a listener to the layout {@link ViewTreeObserver} to wait for the view measurements
     * and then calls {@link #consolideHeights(LinearLayout)}.
     */
    private static void scheduleConsolideHeights(final LinearLayout layout) {

        final ViewTreeObserver viewTreeObserver = layout.getViewTreeObserver();

        if (viewTreeObserver.isAlive()) {
            viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    layout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                    consolideHeights(layout);
                }
            });
        }
    }

    /**
     * Note: you might want to use {@link #scheduleConsolideHeights(android.widget.LinearLayout)}.
     *
     * Takes a {@link android.widget.LinearLayout} and, for each of its child views, sets the height
     * of the child's LayoutParams to the current height of the child.
     *
     * Useful when a {@link android.widget.LinearLayout} that has relative heights (with weights)
     * may display the keyboard. With absolute heights, the layout maintains its aspect when the soft
     * keyboard appears.
     *
     * See: http://stackoverflow.com/q/22534107/1121497
     */
    private static void consolideHeights(LinearLayout layout) {

        for (int i = 0; i < layout.getChildCount(); i++)
        {
            final View child = layout.getChildAt(i);
            final LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) child.getLayoutParams();
            params.height = child.getHeight();
            params.weight = 0;
            child.setLayoutParams(params);
        }
    }
}
Ferran Maylinch
  • 10,919
  • 16
  • 85
  • 100
0

As SiGangteng response in that question that must help you to solve the problem (inside the specific in the manifest)

android:windowSoftInputMode="adjustPan"
Community
  • 1
  • 1
Jorge Cordero
  • 142
  • 2
  • 6