当键盘打开时,包含在ScrollView中的ConstraintLayout仍然会被重新调整大小

3
我希望能够在不改变布局大小的情况下打开键盘。我不想使用adjustNothing,因为我需要我的底部视图之一随着键盘升起。我也不想使用adjustPan,因为它会将整个布局抬离屏幕,这有点丑陋。
因此,我将我的布局(ConstraintLayout)包装在一个ScrollView中,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<layout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

<data>
    <variable
        name="viewModel"
        type="com.mypackage.MyViewModel"/>
</data>

<android.support.design.widget.CoordinatorLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fillViewport="true"
        android:scrollbars="none">

    <!-- I don't want anything in this ConstraintLayout to move or resize when I open the keyboard, hence why I wrapped it in a ScrollView. -->
    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <FrameLayout
            android:id="@+id/scene_container"
            android:layout_width="0dp"
            android:layout_height="0dp"
            app:layout_constraintBottom_toTopOf="@+id/guideline"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent">

            <ImageView
                android:id="@+id/scene"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_gravity="center_horizontal"
                android:adjustViewBounds="true"
                android:background="@color/black"
                android:scaleType="fitCenter"
                android:src="@drawable/grumpy"/>
        </FrameLayout>

        <android.support.constraint.Guideline
            android:id="@+id/guideline"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            app:layout_constraintGuide_percent=".7"/>

        <View
            android:id="@+id/status_bar"
            android:layout_width="0dp"
            android:layout_height="48dp"
            android:background="@color/colorPrimary"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/guideline"/>

        <android.support.v7.widget.RecyclerView
            android:id="@+id/my_recycler"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginBottom="48dp"
            android:clipToPadding="false"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/status_bar"/>

    </android.support.constraint.ConstraintLayout>

    </ScrollView>

    <!-- The bottom sheet contains a 48dp high peekable area (a bar with an EditText) that I need to raise with the keyboard. -->
    <include
        android:id="@+id/bottom_sheet"
        layout="@layout/bottom_sheet"
        app:viewModel="@{viewModel}"/>

</android.support.design.widget.CoordinatorLayout>

对于前两次打开键盘,这个功能表现得很好。以下是我遇到的奇怪问题。每第三次打开键盘时,我的布局都会重新调整大小,并挤在一起,就好像ScrollView不存在一样。这种情况每第三次打开键盘都会如此发生:

1) Open keyboard. Layout remains same size.
   Close keyboard.
2) Open keyboard. Layout remains same size.
   Close keyboard.
3) Open keyboard. *LAYOUT RESIZES/SQUISHES TOGETHER!*
   Close keyboard.

The above cycle repeats as I continue to open/close the keyboard.

有什么办法可以解决这个问题吗?为什么每第三次打开键盘时布局会重新调整大小?
2个回答

4
实际上,如果您将match_parent用作ScrollView子级的大小,当键盘出现并适合ScrollView大小时,它也会重新调整大小。
要了解ScrollView的工作原理,可以将其视为浏览器。在您访问的每个链接上,如果页面不适合浏览器窗口,您将看到滚动条,以便您在页面中导航。ScrollView也是如此,您只需要给它们您想要占据屏幕的大小(就像浏览器窗口一样),并且您可以将所有内容都放在其中(就像网站页面一样),即使它比ScrollView大小还大。
根据这个,您的ConstraintLayout需要一个固定的大小。如果您只希望用户访问其中的所有组件,则可以使用wrap_content。但这不适用于您的情况。您希望它保持原始大小,就像我在您的代码中看到的第一个CoordinatorLayout的大小一样。
我发现唯一修复内部ConstraintLayout以保持原始视图大小的方法是通过代码。
让我们简化您的xml文件,以进行示例:
<android.support.design.widget.CoordinatorLayout
    android:layout_width="match_parent"
    android:id="@+id/parentView"
    android:layout_height="match_parent">

    <ScrollView
        android:id="@+id/scrollViewItem"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.constraint.ConstraintLayout
            android:id="@+id/childView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <!--ALL YOUR ITEMS-->

        </android.support.constraint.ConstraintLayout>

    </ScrollView>

</android.support.design.widget.CoordinatorLayout>

在屏幕加载时,您需要修复 childView 大小。 在 onCreate 中,可以添加以下代码:

private int first = 0;

public class ConstaintLayoutCanScroll extends Activity {

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

        first = childView.getMeasuredHeight();

        final CoordinatorLayout parentView = findViewById(R.id.parentView);
            parentView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                @Override
                public boolean onPreDraw() {
                    if (first < parentView.getMeasuredHeight()) {
                        ConstraintLayout childView = findViewById(R.id.childView);
                        childView.setMinHeight(parentView.getMeasuredHeight());
                        first = childView.getMeasuredHeight();
                    }
                    return true;
                }
            });

    }

}

我使用监听器是因为在 OnCreate 中,大小还没有初始化。

first 在这里是因为 onPreDraw 不仅仅被 Android 调用一次。它是该类的一个变量,默认设置为 0。


1
它运行良好。我还编辑了您的评论以澄清。 - Tuan Nguyen
不要忘记删除preDraw监听器(通常在onPreDraw监听器的第一行完成),否则onPreDraw也会不断被调用,因为Android始终在重新绘制帧。 - Jeff Padgett

0

使用match_parent作为ScrollView子元素的大小并不理想。您应该使用固定大小或wrap_content。在当前设置中,ConstraintLayout试图将其高度设置为ScrollView的高度,并且根据键盘是否显示而更改。

您可以尝试在屏幕上显示ConstraintLayout时将其设置为固定高度。

要测试该方法是否有效,您可以尝试在ConstraintLayout上设置例如android:layout_height="400dp",然后查看是否会发生您提到的“循环”。 如果有效,您可以继续使用ConstraintLayout的实际尺寸匹配屏幕大小。


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