Android双ScrollView自适应布局需求:小屏平分大屏下方拉伸
Android布局适配:动态分配两个ScrollView高度
需求说明:
- 垂直排列两个ScrollView,屏幕高度较小时,两者各占屏幕50%空间(如图1)
- 屏幕高度充足时,下方包含TableView的ScrollView自动拉伸填充剩余可用空间(如图2)
当前使用LinearLayout权重均分的方案无法实现该动态适配效果。
原布局代码:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".cards.CardGoods"> <androidx.appcompat.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:contentInsetStart="0dp" app:menu="@menu/card_step1_menu" > <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingStart="32dp" android:gravity="center"> <TextView android:id="@+id/tv_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/card_goods_p1" style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title" android:singleLine="true" android:maxLines="1" android:ellipsize="end" android:layout_weight="1" android:gravity="center" android:textColor="?attr/colorPrimary" /> <View android:id="@+id/view" android:layout_width="match_parent" android:layout_height="@dimen/divider_height" android:background="@drawable/horizontal_gradient_menu_divider_02" /> </LinearLayout> </androidx.appcompat.widget.Toolbar> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <ScrollView android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <com.google.android.material.textfield.TextInputLayout android:id="@+id/card_Code_n" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginStart="16dp" android:layout_marginTop="16dp" android:layout_marginEnd="16dp" app:startIconDrawable="@drawable/barcode24px" app:startIconTint="@color/deep_purple_100" > <com.google.android.material.textfield.TextInputEditText android:id="@+id/card_Code" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="@string/code" android:maxLines="2" android:backgroundTint="@color/white" android:inputType="textCapSentences" /> </com.google.android.material.textfield.TextInputLayout> <LinearLayout android:id="@+id/lL_edit2" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" android:layout_marginStart="10dp" android:layout_marginEnd="10dp" > <Button android:id="@+id/btn_ean13" android:layout_weight="1" android:layout_width="wrap_content" android:layout_marginStart="10dp" android:layout_marginEnd="5dp" android:layout_marginTop="8dp" android:layout_marginBottom="8dp" android:layout_height="wrap_content" android:text="@string/card_Ean13" android:padding="8dp" /> <Button android:id="@+id/btn_edit_userInfo4" android:layout_weight="1" android:layout_width="wrap_content" android:layout_marginStart="5dp" android:layout_marginEnd="10dp" android:layout_marginTop="8dp" android:layout_marginBottom="8dp" android:layout_height="wrap_content" android:padding="8dp" android:text="@string/card_a1" /> <Button android:id="@+id/btn_edit_userInfo4" android:layout_weight="1" android:layout_width="wrap_content" android:layout_marginStart="5dp" android:layout_marginEnd="10dp" android:layout_marginTop="8dp" android:layout_marginBottom="8dp" android:layout_height="wrap_content" android:padding="8dp" android:text="@string/card_a2" /> </LinearLayout> <com.google.android.material.textfield.TextInputLayout android:id="@+id/card_Nt_n" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginStart="16dp" android:layout_marginTop="16dp" android:layout_marginEnd="16dp" app:startIconDrawable="@drawable/shopping_basket24px" app:startIconTint="@color/deep_purple_100"> <com.google.android.material.textfield.TextInputEditText android:id="@+id/card_Nt" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="@string/name" android:backgroundTint="@color/white" android:inputType="textCapSentences" /> </com.google.android.material.textfield.TextInputLayout> <com.google.android.material.textfield.TextInputLayout android:id="@+id/eiSpinnerLayout" style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginStart="16dp" android:layout_marginTop="16dp" android:layout_marginEnd="16dp" app:startIconDrawable="@drawable/scale24px" app:startIconTint="@color/deep_purple_100"> <androidx.appcompat.widget.AppCompatAutoCompleteTextView android:id="@+id/eiTextView" android:layout_width="match_parent" android:layout_height="wrap_content" tools:ignore="KeyboardInaccessibleWidget" android:clickable="true" android:focusable="false" android:focusableInTouchMode="false" android:hint="@string/ei" /> </com.google.android.material.textfield.TextInputLayout> </LinearLayout> </LinearLayout> </ScrollView> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:background="@color/grey_400" android:layout_weight="1"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <com.evrencoskun.tableview.TableView android:id="@+id/tableview" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="1dp" app:allow_click_inside_cell="true" app:allow_click_inside_column_header="true" app:allow_click_inside_row_header="true"> </com.evrencoskun.tableview.TableView> </LinearLayout> </LinearLayout> </LinearLayout> </androidx.constraintlayout.widget.ConstraintLayout>


解决方案:使用ConstraintLayout实现动态高度适配
替换原布局中的外层LinearLayout,直接用ConstraintLayout管理两个ScrollView的约束,核心逻辑:
- 给上方ScrollView设置最小高度,确保小屏幕时占屏幕50%空间,同时允许空间充足时自适应内容高度
- 下方ScrollView自动填充上方ScrollView底部到屏幕底部的剩余空间
修改后的核心布局代码:
<!-- 替换原布局中的LinearLayout部分 --> <ScrollView android:id="@+id/top_scroll" android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_constraintTop_toBottomOf="@id/toolbar" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" <!-- 小屏幕时至少占屏幕高度的50% --> app:layout_constraintHeight_percent="0.5" app:layout_constraintHeight_min="0dp" <!-- 空间充足时自适应内容高度 --> app:layout_constraintHeight_default="wrap"> <!-- 原上方ScrollView内的内容保持不变 --> </ScrollView> <LinearLayout android:id="@+id/bottom_container" android:layout_width="match_parent" android:layout_height="0dp" android:background="@color/grey_400" app:layout_constraintTop_toBottomOf="@id/top_scroll" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintBottom_toBottomOf="parent"> <com.evrencoskun.tableview.TableView android:id="@+id/tableview" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="1dp" app:allow_click_inside_cell="true" app:allow_click_inside_column_header="true" app:allow_click_inside_row_header="true"> </com.evrencoskun.tableview.TableView> </LinearLayout>
关键属性说明:
app:layout_constraintHeight_percent="0.5":强制上方ScrollView在小屏幕时至少占屏幕高度的50%app:layout_constraintHeight_default="wrap":屏幕高度充足时,上方ScrollView自适应内容高度,不再局限于50%- 下方容器用
layout_height="0dp"配合上下约束,自动填充剩余空间
内容的提问来源于stack exchange,提问作者Сергей Соколов
相关产品推荐
相关产品推荐

