Android CardView横屏布局在不同系统版本设备出现裁剪问题
问题现象
开发的6个CardView组成的功能菜单界面,竖屏状态下两台测试设备显示正常,切换横屏后Android 9设备出现内容裁剪,Android 11设备显示正常。
正常显示设备
- 系统版本:
Android 11
异常裁剪设备
- 系统版本:
Android 9
相关代码
布局XML
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout 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=".activity.TestActivity"> <TextView android:id="@+id/title_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_marginStart="12dp" android:layout_marginTop="12dp" android:layout_marginEnd="12dp" android:layout_marginBottom="0dp" android:text="@string/main_menu_title" android:textSize="30sp" android:textStyle="bold" /> <GridLayout android:layout_width="match_parent" android:layout_height="match_parent" android:columnCount="3" android:rowCount="2" android:layout_below="@id/title_view" android:layout_margin="20dp" android:layout_marginStart="20dp" android:layout_marginTop="20dp" android:layout_marginEnd="20dp" android:layout_marginBottom="10dp"> <androidx.cardview.widget.CardView android:id="@+id/cardStart" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_row="0" android:layout_rowWeight="1" android:layout_column="0" android:layout_columnWeight="1" android:layout_gravity="fill" android:foreground="?selectableItemBackground" app:cardCornerRadius="8dp" app:cardElevation="8dp" app:cardUseCompatPadding="true"> <TextView android:id="@+id/txtCardStart" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical|center_horizontal" android:gravity="center" android:orientation="vertical" android:text="Start" android:textAlignment="center" android:textStyle="bold" app:drawableTopCompat="@drawable/ic_start_black_24dp" /> </androidx.cardview.widget.CardView> <androidx.cardview.widget.CardView android:id="@+id/cardTest" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_row="0" android:layout_rowWeight="1" android:layout_column="1" android:layout_columnWeight="1" android:layout_gravity="fill" android:foreground="?selectableItemBackground" app:cardCornerRadius="8dp" app:cardElevation="8dp" app:cardUseCompatPadding="true"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical|center_horizontal" android:gravity="center" android:orientation="vertical" android:text="Option B" android:textAlignment="center" android:textStyle="bold" app:drawableTopCompat="@drawable/ic_baseline_camera_alt_24" /> </androidx.cardview.widget.CardView> <androidx.cardview.widget.CardView android:id="@+id/cardSettings" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_row="0" android:layout_rowWeight="1" android:layout_column="2" android:layout_columnWeight="1" android:layout_gravity="fill" android:foreground="?selectableItemBackground" app:cardCornerRadius="8dp" app:cardElevation="8dp" app:cardUseCompatPadding="true"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical|center_horizontal" android:gravity="center" android:orientation="vertical" android:text="Option C" android:textAlignment="center" android:textStyle="bold" app:drawableTopCompat="@drawable/ic_settings_black_24dp" /> </androidx.cardview.widget.CardView> <androidx.cardview.widget.CardView android:id="@+id/cardStats" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_row="1" android:layout_rowWeight="1" android:layout_column="0" android:layout_columnWeight="1" android:layout_gravity="fill" android:foreground="?selectableItemBackground" app:cardCornerRadius="8dp" app:cardElevation="8dp" app:cardUseCompatPadding="true"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical|center_horizontal" android:gravity="center" android:orientation="vertical" android:text="Option D" android:textAlignment="center" android:textStyle="bold" app:drawableTopCompat="@drawable/ic_insights_black_24dp" /> </androidx.cardview.widget.CardView> <androidx.cardview.widget.CardView android:id="@+id/cardContact" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_row="1" android:layout_rowWeight="1" android:layout_column="1" android:layout_columnWeight="1" android:layout_gravity="fill" android:foreground="?selectableItemBackground" app:cardCornerRadius="8dp" app:cardElevation="8dp" app:cardUseCompatPadding="true"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical|center_horizontal" android:gravity="center" android:orientation="vertical" android:text="Option E" android:textAlignment="center" android:textStyle="bold" app:drawableTopCompat="@drawable/ic_baseline_email_24" /> </androidx.cardview.widget.CardView> <androidx.cardview.widget.CardView android:id="@+id/cardAbout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_row="1" android:layout_rowWeight="1" android:layout_column="2" android:layout_columnWeight="1" android:layout_gravity="fill" android:foreground="?selectableItemBackground" app:cardCornerRadius="8dp" app:cardElevation="8dp" app:cardUseCompatPadding="true"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical|center_horizontal" android:gravity="center" android:orientation="vertical" android:text="Option F" android:textAlignment="center" android:textStyle="bold" app:drawableTopCompat="@drawable/ic_baseline_info_24" /> </androidx.cardview.widget.CardView> </GridLayout> </RelativeLayout>
主题配置
界面颜色差异由深色模式导致,和裁剪问题无关,主题代码如下:
<style name="AppTheme" parent="Theme.AppCompat.DayNight.DarkActionBar"> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> </style>
问题根因
Android 9及更早版本的系统原生GridLayout存在测量逻辑bug:当GridLayout作为RelativeLayout的子控件,同时设置layout_below属性+自身layout_height="match_parent"时,系统计算GridLayout高度不会扣除上方标题控件占用的空间,直接按整个父布局的全屏高度取值,导致GridLayout底部超出屏幕边界,最后一行卡片被裁剪。
这个bug在Android 10及之后的系统版本中被修复,因此Android 11设备可以正常显示。
另外布局中重复设置layout_margin属性(先设置全局margin再单独设置四个方向margin),也会在低版本系统中放大测量偏差。
通用适配方案
优先使用AndroidX兼容库控件替换系统原生控件,兼容库的bug修复不依赖系统版本,可保证全版本设备表现一致:
- 在模块的build.gradle中引入AndroidX GridLayout依赖:
implementation "androidx.gridlayout:gridlayout:1.0.0"
- 将布局中系统原生
GridLayout替换为AndroidX版androidx.gridlayout.widget.GridLayout,同时修正高度属性避免测量错误,删除重复的margin设置:
<androidx.gridlayout.widget.GridLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_below="@id/title_view" android:layout_alignParentBottom="true" android:columnCount="3" android:rowCount="2" android:layout_marginStart="20dp" android:layout_marginTop="20dp" android:layout_marginEnd="20dp" android:layout_marginBottom="10dp"> <!-- 内部CardView代码无需修改 --> </androidx.gridlayout.widget.GridLayout>
- 可选优化:给CardView内部的TextView添加
android:padding="16dp"属性,避免不同系统下文字、图标尺寸计算偏差导致内容溢出。
如果不想引入额外依赖,也可以将外层根布局替换为ConstraintLayout,通过约束链条和权重分配6个卡片的位置,ConstraintLayout的测量逻辑更稳定,不存在上述低版本兼容问题。
内容的提问来源于stack exchange,提问作者Andy
相关产品推荐
相关产品推荐

