You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android输入框输入时布局/屏幕抖动问题排查

问题描述

在CoordinatorLayout嵌套NestedScrollView的布局中,最后一个TextInputEditText设置了android:minLines="3"和textMultiLine输入类型,输入前两行时整个布局会出现抖动;当输入到第三行(达到minLines设定的行数)或手动调整键盘位置后,抖动停止。移除minLines属性抖动消失,但业务需要保留最小行数设置。

布局代码如下:

<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:paddingStart="@dimen/side_margin"
            android:paddingTop="@dimen/layout_margin_large"
            android:paddingEnd="@dimen/side_margin"
            android:paddingBottom="@dimen/layout_margin_default">

            <!-- Some oother stuff....-->
            
            <com.google.android.material.textview.MaterialTextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="@dimen/layout_margin_default"
                android:text="@string/optional_data" />

            <com.google.android.material.textfield.TextInputLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="@string/brand"
                android:layout_marginTop="@dimen/layout_margin_default"
                app:startIconDrawable="@drawable/baseline_store_24">
                <com.google.android.material.textfield.TextInputEditText
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:inputType="text" />
            </com.google.android.material.textfield.TextInputLayout>

            <com.google.android.material.textfield.TextInputLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="@string/model"
                android:layout_marginTop="@dimen/layout_margin_default"
                app:startIconDrawable="@drawable/baseline_directions_car_24">
                <com.google.android.material.textfield.TextInputEditText
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:inputType="text" />
            </com.google.android.material.textfield.TextInputLayout>

            <com.google.android.material.textfield.TextInputLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="@string/build_year"
                android:layout_marginTop="@dimen/layout_margin_default"
                app:startIconDrawable="@drawable/baseline_event_24">
                <com.google.android.material.textfield.TextInputEditText
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:inputType="date" />
            </com.google.android.material.textfield.TextInputLayout>

            <com.google.android.material.textfield.TextInputLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="@string/license_plate"
                android:layout_marginTop="@dimen/layout_margin_default"
                app:startIconDrawable="@drawable/baseline_pin_24">
                <com.google.android.material.textfield.TextInputEditText
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:inputType="text" />
            </com.google.android.material.textfield.TextInputLayout>

            <com.google.android.material.textfield.TextInputLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="@string/vin"
                android:layout_marginTop="@dimen/layout_margin_default"
                app:startIconDrawable="@drawable/baseline_shield_car_24">
                <com.google.android.material.textfield.TextInputEditText
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:inputType="text" />
            </com.google.android.material.textfield.TextInputLayout>

            <com.google.android.material.textfield.TextInputLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="@string/note"
                android:layout_marginTop="@dimen/layout_margin_default"
                app:startIconDrawable="@drawable/baseline_notes_24">
                <com.google.android.material.textfield.TextInputEditText
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:inputType="textMultiLine"
                    android:minLines="3" />
            </com.google.android.material.textfield.TextInputLayout>

        </LinearLayout>

    </androidx.core.widget.NestedScrollView>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

问题原因

这种抖动是布局重绘与软键盘调整的循环冲突导致的:

  1. 输入前两行时,TextInputEditText的实际高度未达到minLines设定的高度,换行时控件会尝试调整自身高度;
  2. 由于控件在NestedScrollView内,且配合appbar_scrolling_view_behavior,系统会频繁计算布局高度与软键盘的遮挡关系,触发重复的布局重绘;
  3. 当输入到第三行后,控件高度固定为minLines的高度,不再变化,布局重绘停止,抖动消失。

解决方案

方案1:给TextInputLayout设置固定最小高度

直接给外层TextInputLayout设置android:minHeight(值对应3行文本的高度,可通过3 * 单行文本高度计算,比如72dp),同时移除TextInputEditText的minLines:

<com.google.android.material.textfield.TextInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="@string/note"
    android:layout_marginTop="@dimen/layout_margin_default"
    app:startIconDrawable="@drawable/baseline_notes_24"
    android:minHeight="72dp">
    <com.google.android.material.textfield.TextInputEditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="textMultiLine" />
</com.google.android.material.textfield.TextInputLayout>

方案2:禁用NestedScrollView的自动滚动容器行为

在NestedScrollView中添加android:isScrollContainer="false",避免系统因软键盘弹出频繁调整滚动布局:

<androidx.core.widget.NestedScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    android:isScrollContainer="false">

方案3:用固定高度容器包裹输入框

给最后一个TextInputLayout套一个容器,设置最小高度,让输入框在容器内自适应,避免直接影响整个滚动布局的高度计算:

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:minHeight="72dp">
    <com.google.android.material.textfield.TextInputLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/note"
        android:layout_marginTop="@dimen/layout_margin_default"
        app:startIconDrawable="@drawable/baseline_notes_24">
        <com.google.android.material.textfield.TextInputEditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:inputType="textMultiLine"
            android:minLines="3" />
    </com.google.android.material.textfield.TextInputLayout>
</LinearLayout>

内容的提问来源于stack exchange,提问作者igodie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 16:20:30