lpfx
lpfx

Reputation: 1506

Move layout up when soft keyboard is shown

I'm trying to adjust the layout when the soft keyboard appears after an edit text gets focus. Right now if I have many edit text and the keyboard appears, the last edit text are hidden and I can't scroll up.

This is how my layout is builded up:

Template:

<LinearLayout>
    <LinearLayout>
        // header 1
    </LinearLayout>
    <LinearLayout>
        // header 1
    </LinearLayout>
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="0dip"
        android:layout_weight="1"
        android:orientation="vertical">
        // where I inflate view_1
    </LinearLayout>
    <LinearLayout>
        // footer
    </LinearLayout>
</LinearLayout>

View (view_1):

<ScrollView
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:focusable="true"
        android:focusableInTouchMode="true">
        <LinearLayout>
            // ...
        </LinearLayout>
        <LinearLayout>
            // ...
        </LinearLayout>
        <LinearLayout>
            <TextView/>
            <EditText/>
            <TextView/>
            <EditText/>
            <TextView/>
            <EditText/>
            <TextView/>
            <EditText/>
        </LinearLayout>
    </LinearLayout>
</ScrollView>

I already try all kinds of combinations of android:windowSoftInputMode (on manifest.xml and programmatically). I tried to set android:isScrollContainer="false" on the scroll view, but nothing.

I also tried this answer, putting an GlobalLayoutListener in my scroll view, but the onGlobalLayout is not called when the keyboard appears. And the isKeyboardShown is always false.

Upvotes: 6

Views: 25164

Answers (7)

Desmond Lua
Desmond Lua

Reputation: 6290

If you create the Activity using Android Studio Basic Activity wizard (with CoordinatorLayout and theme="@style/AppTheme.NoActionBar"), the default behavior is adjustPan, where the top portion of the activity is push offscreen and the EditText is shown above the Keyboard. You can also change it to adjustResize where the top portion of the activity is maintained.

Edit AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest ...>
    <application ...>
        <activity
            android:name=".TestInputActivity"
            android:label="@string/title_activity_test_input"
            android:windowSoftInputMode="adjustResize"
            android:theme="@style/AppTheme.NoActionBar">
        </activity>
    </application>
</manifest>

Keep in mind though the effect and behavior might differ slightly if you are using Scrolling Activity, such as NestedScrollView.

https://code.luasoftware.com/tutorials/android/move-layout-when-keyboard-shown/

Upvotes: 1

Sarojini2064130
Sarojini2064130

Reputation: 221

The below code is working for me. Just try this example:

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/RelativeAdd"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    tools:context="com.example.scrollview.MainActivity">

    <ScrollView
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center">

            <EditText
                android:id="@+id/editTextUserName"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentTop="true"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="100dp"
                android:ems="10"
                android:inputType="textPersonName"
                android:hint="Name" />

            <EditText
                android:id="@+id/address"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_alignEnd="@+id/editTextUserName"
                android:layout_alignLeft="@+id/editTextUserName"
                android:layout_alignRight="@+id/editTextUserName"
                android:layout_alignStart="@+id/editTextUserName"
                android:layout_below="@+id/editTextUserName"
                android:layout_marginTop="20dp"
                android:ems="10"
                android:inputType="textPersonName"
                android:hint="Address" />

            <Button
                android:id="@+id/buttonLogin"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@+id/address"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="47dp"
                android:text="Button" />
        </RelativeLayout>
    </ScrollView>
</RelativeLayout>

In manifest.xml add these line:

android:theme="@style/AppTheme"    
android:windowSoftInputMode="stateHidden|adjustPan"

Declare AppTheme in style.xml as per your theme requirement. Then if you do not need keyboard comes up while page loads, you can add below line in activity:

getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);

Happy Coding :-)

Upvotes: -1

yehyatt
yehyatt

Reputation: 2414

The best solution I found is to add adjustpan property in the activity<> tag in the manifest.xml file .

<activity
   android:name="MyActivity"
   android:windowSoftInputMode="adjustPan"/>

Upvotes: 8

Ryan
Ryan

Reputation: 3536

This is a late answer, but it may be helpful for anyone that is still looking for an alternative solution. I created a custom ViewTreeObserver.OnGlobalLayoutListener that may fit your use case if you're looking for a way to control the position of the View that you want to ensure is visible when the soft keyboard is shown. Here is a gist to that solution.

The OnGlobalLayoutListener animates changes to the view's translationY property by smoothly moving the view just above the soft keyboard bounds when the keyboard is shown and back to the view's starting position when the the keyboard is dismissed. Let me know if you have any questions on usage.

Upvotes: 3

user196554
user196554

Reputation: 17

android:weightSum="1"

add this

Upvotes: -1

lpfx
lpfx

Reputation: 1506

I ended up doing it my way.

I created a class that implements OnFocusChangeListener to handle all my EditText:

public class EditTextFocusChangeListener implements OnFocusChangeListener {

    private ScrollView scrollView;

    public EditTextFocusChangeListener(ScrollView scrollView) {
        this.scrollView = scrollView;
    }

    @Override
    public void onFocusChange(View view, boolean hasFocus) {
        if(hasFocus) {
            int left = view.getLeft();
            int top = view.getTop();
            int bottom = view.getBottom();
            int keyboardHeight = scrollView.getHeight() / 3;

            // if the bottom of edit text is greater than scroll view height divide by 3,
            // it means that the keyboard is visible
            if (bottom > keyboardHeight)  {
                // increase scroll view with padding
                scrollView.setPadding(0, 0, 0, keyboardHeight);
                // scroll to the edit text position
                scrollView.scrollTo(left, top);
            }
        }
    }
}

Then in the activity, I setted the listener for each edit text:

EditTextFocusChangeListener listener = new EditTextFocusChangeListener(mainScrollView);

editText1 = (EditText) findViewById(R.id.editText1);
editText1.setOnFocusChangeListener(listener);

editText2 = (EditText) findViewById(R.id.editText2);
editText2.setOnFocusChangeListener(listener);

...

editTextN = (EditText) findViewById(R.id.editTextN);
editTextN.setOnFocusChangeListener(listener); 

And for the last edit text, I setted an EditorAction listerner to handle the 'Done' button on soft keyboard - to hide the keyboard and put the scroll view back to its original position:

editTextN.setOnEditorActionListener(new OnEditorActionListener() {
        @Override
        public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
            int result = actionId & EditorInfo.IME_MASK_ACTION;
            switch(result) {
                // user taped on keyboard DONE button
                case EditorInfo.IME_ACTION_DONE:
                    // put the scroll view back to its original position
                    mainScrollView.setPadding(0, 0, 0, 0);
                    // hide keyboard
                    ((InputMethodManager) getApplicationContext().getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(v.getWindowToken(), 0);
                    // remove focus from any edit text
                    LinearLayout scrollViewLL = (LinearLayout) mainScrollView.getChildAt(0);
                    scrollViewLL.requestFocus();
                break;
            }
            return false;
        }
    });

And finally, a way to handle when the user touches outside an edit text to hide the keyboard and put the scroll view back to its original position (found this on web and changed a little to fit my needs):

public void setupUI(View view) {
    // Set up touch listener for non-text box views to hide keyboard.
    if (!(view instanceof EditText)) {
        view.setOnTouchListener(new OnTouchListener() {
            public boolean onTouch(View v, MotionEvent event) { 

                // put the scroll view back to its original position
                if (v instanceof ScrollView) {
                    v.setPadding(0, 0, 0, 0);
                    LinearLayout scrollViewLL = (LinearLayout) ((ScrollView) v).getChildAt(0);
                    scrollViewLL.requestFocus();
                }

                hideKeyboard();
                return false;
            }
        });
    }

    // If a layout container, iterate over children and seed recursion.
    if (view instanceof ViewGroup) {
        for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
            View innerView = ((ViewGroup) view).getChildAt(i);
            setupUI(innerView);
        }
    }
}

Upvotes: 3

anil
anil

Reputation: 2113

Put all of your top code in ScrollView, not just view_1. This allows you to move all the parent layout on click by any child EditText.

EDIT: view_1 in this case MUST NOT contains ScrollView!

Upvotes: 1

Related Questions