前言
在某些情况下,我们需要将装载数据的 RecyclerView 或 leanback-VerticalGridView 控件固定在特定尺寸下,以充分利用屏幕尺寸。
但在固定尺寸后,进行焦点移动时,往往会存在 Item 被切或超出布局的问题,即:焦点移动时视图形变的问题。本文为此问题提供了一个解决办法,下面来看看具体问题和解决办法。
需求描述
如下图,需要用列表控件装载已配对的设备(即:图中 Paired devices下面的列表内容),我们可以使用 ListView 或 RecyclerView,但在 TV 上显然我们有更好的选择,即 leanback 系列的 VerticalGridView,这三个控件可以依自身情况使用,但是都会存在焦点移动时视图形变的问题。
实现效果
1. Item 被切
Item 被切很好理解,因为我们对 Item 聚焦时做了放大动效,会超出布局尺寸,此时在父控件设置 clipChildren 为 false,让其不进行裁剪即可。
2. 超出布局
3. 正常效果
问题解析
前文提到了我们可以轻而易举解决 Item 被切的问题,但对于超出布局这题却没有好的解决办法——列表+固定布局+聚焦放大动效。
目前我这边想到一种方式并在实战中使用,虽然稍显蹩脚,但能较好满足需求。下面看一下两者的代码,分析不同之处,解决思路显而易见。
超出布局时 XML 代码如下
<androidx.leanback.widget.VerticalGridView
android:id="@+id/vgv_ble_paired"
android:layout_width="@dimen/size_1112_base"
android:layout_height="@dimen/size_280_base"
android:layout_marginStart="@dimen/size_206_base"
android:layout_marginTop="@dimen/size_24_base"
android:clipChildren="false" />
正常效果时 XML 代码如下
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/size_161_base"
android:layout_marginTop="@dimen/size_19_base">
<androidx.leanback.widget.VerticalGridView
android:id="@+id/vgv_ble_paired"
android:layout_width="@dimen/size_1202_base"
android:layout_height="@dimen/size_290_base"
android:clipChildren="false"
android:clipToPadding="false"
android:paddingStart="@dimen/size_45_base"
android:paddingTop="@dimen/size_5_base"
android:paddingEnd="@dimen/size_45_base"
android:paddingBottom="@dimen/size_5_base" />
</FrameLayout>
细节讨论
需求 UI 图中了解到,列表总高度为 280px,总宽度为 1112px,左间距为 206px,上间距为 24px,如上面超出布局时的 XML 布局代码所示。
正如软件中遇到解决不了的问题时,加一个中间件往往可以使问题迎刃而解,所以这里采取的解决方案如斯简单粗暴——加一个中间层 FrameLayout 。
Framelayout 限定对外布局尺寸,而 VerticalGridView 通过设置 padding 对内限定超出布局即可,这里保证列表整体位置不变即可,有如下逻辑需注意:
- paddingStart 和 paddingEnd 的值应为聚焦放大后超出布局的宽度,同理, paddingTop 和 paddingBottom 的值应为聚焦放大后超出布局的高度;
- VerticalGridView 的 paddingStart 与 Framelayout 的 layout_marginStart 之和,应为 UI 图中列表左间距 206px;
- VerticalGridView 的宽高需要加上左右和上下的 padding 距离;
- VerticalGridView 的 clipChildren 和 clipToPadding 都为 false。
小结
本问题主要在 Android TV 或投影仪等硬件设备上出现,且本文所采取方案并不是最终解决办法,请慎重使用。