6

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.

Community
  • 1
  • 1
lpfx
  • 1,476
  • 4
  • 18
  • 40

7 Answers7

8

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"/>
Muhammed Refaat
  • 8,914
  • 14
  • 83
  • 118
yehyatt
  • 2,295
  • 3
  • 28
  • 31
3

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);
        }
    }
}
lpfx
  • 1,476
  • 4
  • 18
  • 40
  • Hi @lpfx, may I know why /3 to calculate height of keyboard ? – cgr Jan 14 '16 at 15:49
  • I assumed that the keyboard height takes 1/3 of the screen. It's not a great solution, but it worked for the devices I had to support. This may break for small screens. You can set a different value for it. PS: my app was only in portrait mode. – lpfx Jan 15 '16 at 12:34
3

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.

Ryan
  • 3,414
  • 2
  • 27
  • 34
1

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!

anil
  • 2,083
  • 21
  • 37
  • Thanks for your answer, but I can't. My "top code" is a template that should not scroll. It contains headers and a footer that are fixed and the views inflated between should scroll. In this template, I inflate all views of my app, `view_1` is just one of the views of the app. – lpfx Jan 20 '15 at 11:10
  • I suppose the keyboard cannot moves the parent layout to show you bottom widgets in this case. – anil Jan 20 '15 at 11:21
  • The best solution is simplify the interface. The worst solution is ScrollView in ScrollView: http://stackoverflow.com/a/11554823/3345366 – anil Jan 20 '15 at 11:28
  • My idea is to move only the "inner layout". The headers and footer will remain fixed and when the user taps on an edit text of `view_1`, only `view_1` will move to show the edit text above the keyboard. – lpfx Jan 20 '15 at 11:44
  • And if there is a distance between bottom of view_1 and footer? you can try to set `overscrollMode` in `ScrollView` to `always`, but I don't really think it helps. – anil Jan 20 '15 at 12:00
  • 1
    No, it didn't help :( Everything in android is so random! – lpfx Jan 20 '15 at 17:23
  • I changed the layout as you suggested. Now all my "top code" is inside a `ScrollView` and there is no `ScrollView` in `view_1` anymore. And in manifest I put `android:windowSoftInputMode="adjustResize"`. But still nothing, when for example the first `EditText` get focus, I can't see the others because of the keyboard and I can't scroll either. – lpfx Jan 21 '15 at 11:03
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/69299/discussion-between-anil-and-lpfx). – anil Jan 21 '15 at 13:21
1

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/

Desmond Lua
  • 6,142
  • 4
  • 37
  • 50
-1
android:weightSum="1"

add this

Ghasem
  • 14,455
  • 21
  • 138
  • 171
user196554
  • 17
  • 4
-1

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 :-)

claymation
  • 2,475
  • 4
  • 27
  • 36
Sarojini2064130
  • 221
  • 3
  • 7