悬浮窗,ViewPager2内嵌套RecyclerView,RecyclerView高度异常的问题分析

1 背景

在一个Adnroid项目中,使用到了悬浮窗,其中有一个需求是以分页的显示显示媒体item,每一页中展示的媒体item是一个网格列表的形式显示的。

原型图如下:

2 实现方案

  1. 上述需求实现分页采用ViewPager2,在xml中的width和height使用match_parent。因为有indicator故外部又套了一个布局。xml为card_page.xml,具体的布局如下:
xml 复制代码
<?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"
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    xmlns:tools="http://schemas.android.com/tools">

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/vp_card"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <FrameLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/dp_32"
        android:layout_marginBottom="@dimen/dp_48"
        android:layout_marginEnd="@dimen/dp_16"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <com.xxx.VerticalDotsIndicator
            android:layout_gravity="center_vertical"
            android:id="@+id/vdi"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:visibility="gone"
            tools:visibility="visible" />
    </FrameLayout>


</androidx.constraintlayout.widget.ConstraintLayout>

这个布局是以代码动态添加的悬浮窗的根View中的,所以这里备注下悬浮窗WindowManager#addView函数的View其对应的布局,xml为window_card.xml,如下:

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:id="@+id/ll_content"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    tools:ignore="RtlSymmetry">

    <LinearLayout
        android:id="@+id/ll_placeholder"
        android:layout_width="wrap_content"
        android:layout_height="@dimen/dp_112"
        android:gravity="center_vertical"
        android:orientation="vertical"
        android:paddingStart="@dimen/dp_116"
        android:paddingEnd="@dimen/dp_48"
        android:visibility="visible"
        tools:visibility="visible">

        <TextView
            android:visibility="invisible"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ellipsize="start"
            android:maxWidth="@dimen/dp_384"
            android:minWidth="@dimen/dp_122"
            android:singleLine="true"
            android:textColor="@color/white_ccFFFFFF"
            android:textSize="@dimen/sp_32" />


    </LinearLayout>

    <com.xxx.view.CardContentLayout
        android:id="@+id/ll_card_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" />


</LinearLayout>

即需要将card_page.xml的布局动态添加到window_card.xml中的ll_card_container中。然后动态设置ll_content的宽度和高度为一个固定值,对应测量规范MeasureSpec中的exactly。

  1. 每个page的媒体网格列表是使用RecyclerView,布局管理器采用GridLayoutManager。对应的布局xml如下:
xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>

    </data>

    <com.xxx.view.RecyclerViewAtViewPager2
        android:paddingEnd="@dimen/dp_18"
        android:id="@+id/rv_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:ignore="RtlSymmetry" />

</layout>

3 问题描述

在实际开发调试过程中发现如果有多个page,且最后一个page中的媒体item数目不够2行,那么rv_container的RecyclerView的高度是小于vp_card ViewPager2的高度,即实际上是一行itemView对应的高度。

这就会导致在翻到最后一个page,该page同时也显示了上一个page中的item,这是个明显的bug。

4 问题分析与解决

在xml的布局中明明指定了RecyclerView的height为match_parent,即Recycler的高度应该等于ViewPager2的高度的。

在 2.1 我们提到 "即需要将card_page.xml的布局动态添加到window_card.xml中的ll_card_container中。然后动态设置ll_content的宽度和高度为一个固定值,对应测量规范MeasureSpec中的exactly。",这里比较关键,我们只设置了ll_content的高度,并没有设置vp_card ViewPager2的高度。又联想到如果在一个Activity中使用ViewPager2内部嵌套RecyclerView并没有出现过类似的奇怪问题。所以我们可以通过动态设置ViewPager2或ViewPager2的直接父View的高度方式解决此问题。

在经过实际验证该方案确实可行。

相关推荐
阿巴斯甜17 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker18 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq952719 小时前
Andorid Google 登录接入文档
android
黄林晴20 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab1 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿1 天前
Android MediaPlayer 笔记
android
Jony_1 天前
Android 启动优化方案
android
阿巴斯甜1 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇1 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_2 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android