Move layout up when soft keyboard is shown

泄露秘密 提交于 2019-11-27 18:54:21

问题


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.


回答1:


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"/>



回答2:


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.




回答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);
        }
    }
}



回答4:


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!




回答5:


android:weightSum="1"

add this




回答6:


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/




回答7:


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



来源:https://stackoverflow.com/questions/28029264/move-layout-up-when-soft-keyboard-is-shown

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!