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>
问题原因
这种抖动是布局重绘与软键盘调整的循环冲突导致的:
- 输入前两行时,
TextInputEditText的实际高度未达到minLines设定的高度,换行时控件会尝试调整自身高度; - 由于控件在
NestedScrollView内,且配合appbar_scrolling_view_behavior,系统会频繁计算布局高度与软键盘的遮挡关系,触发重复的布局重绘; - 当输入到第三行后,控件高度固定为
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
相关产品推荐
相关产品推荐

