悬浮窗,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的高度方式解决此问题。

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

相关推荐
huwuhang7 小时前
Winkawaks街机游戏模拟器整合ROM版 1.65 汉化修正完整版 2026.03.30
android·游戏·游戏机
yitian_hm7 小时前
MySQL主从复制与读写分离实战指南
android·mysql·adb
NEGl DRYN7 小时前
Plugin ‘mysql_native_password‘ is not loaded`
android·数据库·mysql
Derrick__18 小时前
Android混淆和加密技术
android·jvm·python
sunwenjian8868 小时前
MySQL加减间隔时间函数DATE_ADD和DATE_SUB的详解
android·数据库·mysql
ictI CABL9 小时前
MySQL Workbench菜单汉化为中文
android·数据库·mysql
放学以后Nicetry11 小时前
Android SELinux 指南:从基本概念到实战修复
android
CCIE-Yasuo11 小时前
《永恒战士2-无双战神》无限金币版(提供apk下载)安卓Android逆向记录学习-Deepseek-AI辅助
android·java·学习·游戏
jzlhll12312 小时前
kotlin flow去重distinctUntilChanged vs distinctUntilChangedBy
android·开发语言·kotlin
渡我白衣12 小时前
【MySQL基础】(3):MySQL库与表的操作
android·数据库·人工智能·深度学习·神经网络·mysql·adb