当软键盘弹出时移动布局

6
我正在尝试在编辑文本获得焦点后调整布局,以便软键盘出现。现在,如果我有很多编辑文本并且键盘出现,最后一个编辑文本将被隐藏,我无法向上滚动。
这是我的布局结构:
模板:
<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_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>

我已经尝试了各种组合的android:windowSoftInputMode(在manifest.xml和编程中)。我尝试在滚动视图上设置android:isScrollContainer="false",但是没有效果。我还尝试了这个答案,在我的滚动视图中放置一个GlobalLayoutListener,但是当键盘出现时onGlobalLayout不会被调用。而且isKeyboardShown始终为false。
7个回答

8
我找到的最佳解决方案是在manifest.xml文件中的标签中添加adjustpan属性。
<activity
   android:name="MyActivity"
   android:windowSoftInputMode="adjustPan"/>

我尝试过了,但没有成功。我的解决方案现在非常好用。无论如何还是谢谢。 - lpfx
1
这应该被标记为答案,它对我有用 (: - Denys Vitali

3

我最终按照自己的方式完成了它。

我创建了一个实现OnFocusChangeListener接口的类来处理所有的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);
            }
        }
    }
}

然后在活动中,我为每个编辑文本设置了监听器:

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

对于最后的编辑文本,我设置了一个EditorAction监听器来处理软键盘上的“完成”按钮 - 隐藏键盘并将滚动视图恢复到其原始位置:

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

最后,有一种方法可以处理用户触摸编辑文本以外区域的情况,隐藏键盘并将滚动视图恢复到原始位置(我在网上找到了这个方法,并进行了一些修改以适应我的需要):

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,我能知道为什么要用/3来计算键盘的高度吗? - cgr
我假设键盘高度占屏幕的1/3。虽然不是最好的解决方案,但对于我要支持的设备有效。这在小屏幕上可能会出现问题。您可以为其设置不同的值。PS:我的应用程序只支持纵向模式。 - lpfx

3
这是一个晚回答,但如果任何人仍在寻找替代解决方案,这可能对您有所帮助。我创建了一个自定义的ViewTreeObserver.OnGlobalLayoutListener,如果您正在寻找一种控制在软键盘显示时要确保可见的View位置的方法,则可以适用于您的用例。这里是一个代码片段OnGlobalLayoutListener通过平滑地将视图移动到软键盘边界上方来动画更改视图的translationY属性,并在键盘显示时将其移回视图的起始位置。如果您对用法有任何疑问,请告诉我。

这对我很有效,非常感谢!如果这里也包括gist就更好了。 - stevyhacker

1
如果您使用Android Studio的基本活动向导(带有CoordinatorLayout和theme="@style/AppTheme.NoActionBar"),则默认行为是adjustPan,即将活动的顶部部分推到屏幕外,并在键盘上方显示EditText。您还可以将其更改为adjustResize,其中活动的顶部部分被保留。请编辑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>

请记住,如果您使用滚动活动,例如NestedScrollView,则效果和行为可能略有不同。

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


1
将所有顶部代码放在ScrollView中,而不仅仅是view_1。这样可以通过任何子EditText单击移动所有父布局。 编辑:在此情况下,view_1绝不能包含ScrollView

谢谢您的回答,但我做不到。我的“顶部代码”是一个模板,不应该滚动。它包含固定的标题和页脚,而在它们之间填充的视图应该可以滚动。在这个模板中,我填充了应用程序的所有视图,“view_1”只是应用程序的其中一个视图。 - lpfx
我想在这种情况下,键盘无法移动父布局以显示底部小部件。 - anil
我的想法是只移动“内部布局”。标题和页脚将保持固定,当用户点击view_1的编辑文本时,只有view_1会移动以显示键盘上方的编辑文本。 - lpfx
如果视图view_1底部和页脚之间有距离怎么办?你可以尝试在ScrollView中设置overscrollMode为always,但我并不认为这会有所帮助。 - anil
1
不,它没有帮助 :( Android 中的一切都是如此随机! - lpfx
显示剩余3条评论

-1
以下代码对我有效。请尝试这个例子:
<?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>

在 manifest.xml 中添加这些行:

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

根据您的主题要求,在style.xml中声明AppTheme。如果您不希望页面加载时键盘弹出,可以在activity中添加以下行:

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

编程愉快 :-)


-1
android:weightSum="1"

添加这个


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接