当前位置: 首页 > news >正文

Android-自适用高度的ViewPager

需求

在项目中,我们常常遇到需要动态调整 ViewPager 的高度,以适应其内容大小的需求。默认情况下,ViewPager 的高度是固定的,无法根据每个页面的内容高度进行调整。这会导致在内容高度不一致时,出现不必要的空白区域或者内容被裁剪的情况。为了解决这个问题,我们设计了一个 AutoHeightViewPager,能够根据当前显示页面的内容高度动态调整自身的高度,保证内容完整且没有多余的空白。

效果

在这里插入图片描述
在这里插入图片描述

实现思路

1. 动态高度调整

首先,我们需要一个自定义的 ViewPager 类 AutoHeightViewPager,这个类可以根据当前页面的内容高度来动态调整自身的高度。通过重写 onMeasure 方法,可以在滑动过程中动态计算页面的高度并调整布局。

2. 监听页面滑动事件

为了平滑过渡,我们需要监听页面的滑动过程,并计算滑动比例,将当前页面的高度与下一个页面的高度按比例过渡,实现平滑过渡效果。

3. 自定义 Adapter

自定义的 PagerAdapter 必须实现一个接口 AutoHeightPager,用于获取指定位置页面的 View,这样我们可以测量页面内容的高度。

实现代码

1. AutoHeightViewPager

package com.yxlh.androidxy.demo.ui.viewpager.vpimport android.content.Context
import android.util.AttributeSet
import android.view.View
import androidx.viewpager.widget.PagerAdapter
import androidx.viewpager.widget.ViewPagerinterface AutoHeightPager {fun getView(position: Int): View?
}class AutoHeightViewPager @JvmOverloads constructor(context: Context,attrs: AttributeSet? = null
) : ViewPager(context, attrs) {private var lastWidthMeasureSpec: Int = 0private var currentHeight: Int = 0private var lastPosition: Int = 0private var isScrolling: Boolean = falseinit {addOnPageChangeListener(object : SimpleOnPageChangeListener() {override fun onPageScrolled(position: Int,positionOffset: Float,positionOffsetPixels: Int) {if (positionOffset == 0f) {isScrolling = falserequestLayout()return}val srcPosition = if (position >= lastPosition) position else position + 1val destPosition = if (position >= lastPosition) position + 1 else positionval srcHeight = getViewHeight(srcPosition)val destHeight = getViewHeight(destPosition)currentHeight = (srcHeight + (destHeight - srcHeight) *if (position >= lastPosition) positionOffset else 1 - positionOffset).toInt()isScrolling = truerequestLayout()}override fun onPageScrollStateChanged(state: Int) {if (state == SCROLL_STATE_IDLE) {lastPosition = currentItem}}})}override fun setAdapter(adapter: PagerAdapter?) {require(adapter == null || adapter is AutoHeightPager) { "PagerAdapter must implement AutoHeightPager." }super.setAdapter(adapter)}private fun getViewHeight(position: Int): Int {val adapter = adapter as? AutoHeightPager ?: return 0return run {val view = adapter.getView(position) ?: return 0view.measure(lastWidthMeasureSpec,MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED))view.measuredHeight}}override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {lastWidthMeasureSpec = widthMeasureSpecvar heightSpec = heightMeasureSpecif (isScrolling) {heightSpec = MeasureSpec.makeMeasureSpec(currentHeight, MeasureSpec.EXACTLY)} else {getViewHeight(currentItem).takeIf { it > 0 }?.let {heightSpec = MeasureSpec.makeMeasureSpec(it, MeasureSpec.EXACTLY)}}super.onMeasure(widthMeasureSpec, heightSpec)}
}

2. AutoHeightPagerAdapter

package com.yxlh.androidxy.demo.ui.viewpagerimport android.view.View
import android.view.ViewGroup
import androidx.viewpager.widget.PagerAdapter
import com.yxlh.androidxy.demo.ui.viewpager.vp.AutoHeightPagerclass AutoHeightPagerAdapter : PagerAdapter(), AutoHeightPager {private val viewList = mutableListOf<View>()override fun instantiateItem(container: ViewGroup, position: Int): Any {val view = viewList[position]val parent = view.parent as? ViewGroupparent?.removeView(view)container.addView(view)return view}override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {container.removeView(`object` as View)}fun setViews(views: List<View>) {viewList.clear()viewList.addAll(views)notifyDataSetChanged()}override fun getView(position: Int): View? {return viewList.getOrNull(position)}override fun getCount(): Int {return viewList.size}override fun isViewFromObject(view: View, `object`: Any): Boolean {return view == `object`}
}

3. Activity 代码

package com.yxlh.androidxy.demo.ui.viewpagerimport android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import com.yxlh.androidxy.R
import com.yxlh.androidxy.demo.ui.viewpager.vp.AutoHeightViewPagerclass VpActivity : AppCompatActivity() {private var mAutoHeightVp: AutoHeightViewPager? = nullprivate var mAdapter: AutoHeightPagerAdapter? = nulloverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_vp)val viewList: MutableList<View> = ArrayList()viewList.add(LayoutInflater.from(this).inflate(R.layout.view_demo_1, null))viewList.add(LayoutInflater.from(this).inflate(R.layout.view_demo_2, null))mAutoHeightVp = findViewById(R.id.viewpager)mAutoHeightVp?.setAdapter(AutoHeightPagerAdapter().also { mAdapter = it })mAdapter?.setViews(viewList)mAutoHeightVp?.setCurrentItem(1)}
}

4. 布局 XML

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"><androidx.core.widget.NestedScrollViewandroid:layout_width="match_parent"android:layout_height="wrap_content"app:layout_constraintTop_toTopOf="parent"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><com.yxlh.androidxy.demo.ui.viewpager.vp.AutoHeightViewPagerandroid:id="@+id/viewpager"android:layout_width="match_parent"android:layout_height="wrap_content" /><ImageViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:adjustViewBounds="true"android:scaleType="fitXY"android:src="@drawable/vp_content" /></LinearLayout></androidx.core.widget.NestedScrollView></androidx.constraintlayout.widget.ConstraintLayout>

总结

通过自定义 ViewPager 的动态高度适配功能,我们可以解决内容高度不一致导致的布局问题。这种方案可以适应不同页面内容的高度变化,实现平滑的过渡效果,非常适用于动态内容展示的场景。

相关文章:

Android-自适用高度的ViewPager

需求 在项目中&#xff0c;我们常常遇到需要动态调整 ViewPager 的高度&#xff0c;以适应其内容大小的需求。默认情况下&#xff0c;ViewPager 的高度是固定的&#xff0c;无法根据每个页面的内容高度进行调整。这会导致在内容高度不一致时&#xff0c;出现不必要的空白区域或…...

代码随想录day38|| 322零钱兑换 279完全平方数 139单词拆分

322零钱兑换 力扣题目链接 题目描述&#xff1a; 给你一个整数数组 coins &#xff0c;表示不同面额的硬币&#xff1b;以及一个整数 amount &#xff0c;表示总金额。 计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额&#xff0c…...

Cesium天空盒子(Skybox)制作(js代码)和显示

介绍 在Cesium中&#xff0c;星空背景是通过天空盒子方式&#xff08;6张图片&#xff09;来显示的&#xff0c;原生的图片分辨率太低&#xff0c;本项目用于生成天空盒子的6张图片。最终生成的6个图片大小约为500kb(每个)&#xff0c;格式为jpg&#xff0c;总共的恒星数目约为…...

JAVA中的缓冲流BufferedInputStream

在Java中&#xff0c;BufferedInputStream 是一种用于包装其他输入流&#xff08;如 FileInputStream&#xff09;的过滤流。它通过内部缓冲区机制提高了输入流处理的效率。使用缓冲流可以减少读取数据的次数&#xff0c;因为每次从输入流读取数据时&#xff0c;BufferedInputS…...

WindowContainerTransaction类详解(一)

1、WindowContainerTransaction是什么&#xff1a; windowContainerTransaction类的对象是用来存储对windowContainer的修改的一个集合&#xff0c;windowContainer。因为应用侧是无法直接操作windowContainer的&#xff0c;如果应用侧需要修改windowContainer的话&#xff0c…...

安装NFS扩展

#添加helm源 helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner #创建个namespace(可选,主要是为了查看资源方便) kubectl create ns nfs-sc-default #使用helm安装(10.1.129.86为NFS地址,/home/data/nfs…...

计算机网络——运输层(进程之间的通信、运输层端口,UDP与TCP、TCP详解)

运输层协议概述 进程之间的通信 运输层向它上面的应用层提供通信服务。 当网络边缘部分的两台主机使用网络核心部分的功能进行端到端的通信时&#xff0c;都要使用协议栈中的运输层&#xff1b;而网络核心部分中的路由器在转发分组时只用到下三层的功能。 Q1&#xff1a;我们…...

代码随想录算法训练营第一天 | 二分查找

文章目录 Leetcode704 二分查找二分法的使用前提:区间选择其他注意事项 Leetcode27 移除元素解题思路:优化思路 Leetcode704 二分查找 链接&#xff1a;https://leetcode.cn/problems/binary-search/ 代码随想录: https://programmercarl.com/ 时间复杂度: O(logN) 空间复杂度:…...

python相关知识

1、注释 共有三种&#xff1a;#、 、””” ””” 2、数据类型 整数、浮点、字符串、布尔、列表、元组、集合、字典 num1 666、num2 3.14、t1 True、t2 False、 列表&#xff1a;list [1,2,3,4] 元组&#xff1a;tuple (11,aaa,ddd,3) 字典&#xff1a;dict {li…...

Visual Studio 2022 LNK2001无法解析的外部符号 _wcscat_s 问题记录

ANSI C程序中&#xff0c;用到了wcsrchr、wcsncpy_s、wcscat_s、wcscpy_s等几个字符串函数&#xff0c;但是编译时提示&#xff1a; 错误 LNK2001 无法解析的外部符号 _wcscat_s 查了挺多帖子&#xff0c;没有解决。 https://bbs.csdn.net/topics/250012844 解决VS编译…...

Java高并发处理机制

高并发处理的思路&#xff1a; 扩容&#xff1a;水平扩容、垂直扩容缓存&#xff1a;将基础的数据放入缓存进行处理使用SpringCloud的注册中心&#xff0c;分服务注册到同一个注册中心&#xff0c;服务器检测使用Spring的熔断操作&#xff0c;检测服务器的心跳那个正常随机跳转…...

7 数据存储单位,整型、浮点型、字符型、布尔型数据类型,sizeof 运算符

目录 1 数据类型的分类 2 数据存储单位 2.1 位 2.2 字节 2.3 其余单位 3 整数类型 3.1 基本介绍 3.2 整型的类型 3.2.1 整数类型多样性的原因 3.2.2 整型类型之间的相对大小关系 3.3 整型注意事项 3.4 字面量后缀 3.5 格式占位符 3.6 案例&#xff1a;声明并输出…...

导游职业资格考试真题题库

导游职业资格考试真题题库 80.重庆有"雾都"之称。壁山区的()全年雾日多204天&#xff0c;堪称"世界之最"。 A.枇杷山 B.雾灵山 C.云雾山 D.四姑娘山 答案&#xff1a;C 81.我国最具热带海洋气候特色的地方为&#xff08;&#xff09;。 A.广西壮族…...

【Rust】使用开源项目搭建瓦片地图服务

本文通过获取在线和离线地图数据&#xff0c;使用开源Rust项目搭建瓦片地图服务&#xff0c;并使用DevExpress的MapControl控件使用自建地图服务 获取地图数据 获取地图数据有很多种方式&#xff0c;这里分别用在线和离线地图数据举例说明 在线下载瓦片地图 打开在线瓦片地…...

【面试宝典】mysql常见面试题总结(上)

一、MySQL 中有哪几种锁&#xff1f; MySQL中的锁机制是数据库并发控制的重要组成部分&#xff0c;它用于管理多个用户对数据库资源的访问&#xff0c;确保数据的一致性和完整性。MySQL中的锁可以根据不同的分类标准进行分类&#xff0c;以下是一些常见的分类方式及对应的锁类…...

第1章 初识C语言

第1章 初识C语言 1.1 C语言概述 1.1.1 C语言的发展历史 C语言的原型为ALGOL 60语言&#xff08;也称A语言&#xff09;。 1963年 剑桥大学将ALGOL 60语言发展成为GPL语言。 1967年 剑桥大学的Matin Richards简化GPL&#xff0c;产生了BGPL语言。 1970年 美国贝尔实验室的Ken…...

【考研数学】定积分应用——旋转体体积的计算(一文以蔽之)

目录 一、如何计算旋转体体积&#xff1f;思考一个小例子 二、旋转体体积的二重积分表达式 三、用真题&#xff0c;小试牛刀 定积分的应用中&#xff0c;有一类题是求解旋转体的体积问题。 相较于记忆体积计算公式&#xff0c;有一种通法求解体积更不容易出错&#xff1a;二重…...

PHP移动端商城分销全平台全端同步使用

&#x1f4f1;【掌中购物新纪元&#xff1a;探索移动端购物商城系统的无限魅力】&#x1f6cd;️ &#x1f680; 随时随地&#xff0c;购物自由新体验 在这个快节奏的时代&#xff0c;移动端购物商城系统彻底颠覆了传统购物方式&#xff0c;让消费者享受到了前所未有的便捷与…...

TLE8386-2EL:汽车级DC-DC转换器中文资料书

描述 TLE8386-2EL是一款具有内置保护功能的低端感应升压控制器。该器件的主要功能是将输入电压升高&#xff08;升压&#xff09;到更大的输出电压。开关频率可从100kHz调整至700kHz&#xff0c;并可与外部时钟源同步。 TLE8386-2EL的独特功能可将关断电流消耗降至 <2μA。该…...

EasyRecovery17中文mac苹果电脑版数据恢复软件 永久免费破解版下载

&#x1f389; 数据丢失不再是噩梦&#xff01;EasyRecovery17中文版来拯救你的硬盘啦&#xff01; 各位小伙伴们&#xff0c;有没有遇到过重要文件一不小心就消失无踪的尴尬情况&#xff1f;别担心&#xff0c;今天就给大家种草一款神奇的工具——EasyRecovery17中文版&#x…...

从CNN到Mamba:为什么这个轻量级双分支结构在医学图像分类中表现更好?

从CNN到Mamba&#xff1a;轻量级双分支结构如何重塑医学图像分类范式 医学影像分析正面临前所未有的挑战——随着CT、MRI、超声等成像技术的普及&#xff0c;每天产生的医学图像数据呈指数级增长。传统CNN架构在应对高分辨率医学图像时&#xff0c;往往陷入局部特征提取的局限&…...

别再怕凸优化!手把手教你估算二阶锥(SOC)和线性矩阵不等式(LMI)问题的计算量

凸优化实战指南&#xff1a;SOC与LMI问题计算量估算的工程化思维 在无线通信系统设计和信号处理算法开发中&#xff0c;工程师们经常需要面对各种优化问题。当论文中那些充满二阶锥&#xff08;SOC&#xff09;和线性矩阵不等式&#xff08;LMI&#xff09;的数学公式摆在面前…...

微信公众号模板消息推送实战:从配置到代码实现(PHP版)

微信公众号模板消息推送实战&#xff1a;PHP开发全流程指南 在移动互联网时代&#xff0c;微信公众号已成为企业与用户沟通的重要桥梁。模板消息作为微信生态中的关键功能&#xff0c;能够实现精准、高效的信息触达。本文将带领PHP开发者从零开始&#xff0c;完整掌握模板消息推…...

AI运维管理与安全防护设备功率MOSFET选型方案——高效、可靠与智能驱动系统设计指南

随着智能化运维与主动安全防护需求的爆发式增长&#xff0c;AI边缘计算节点、智能传感器与安全执行单元已成为现代基础设施管理的核心。其电源管理与信号驱动系统作为设备可靠运行与实时响应的基石&#xff0c;直接决定了系统的能效、稳定性及防护等级。功率MOSFET作为该系统中…...

零基础掌握LunaTranslator:视觉小说翻译工具全流程实战指南

零基础掌握LunaTranslator&#xff1a;视觉小说翻译工具全流程实战指南 【免费下载链接】LunaTranslator 视觉小说翻译器 / Visual Novel Translator 项目地址: https://gitcode.com/GitHub_Trending/lu/LunaTranslator LunaTranslator作为一款专注于视觉小说翻译的开源…...

大模型开发:裸辞还是在职?算清这笔账,转型之路少走弯路!

文章探讨了在大模型开发转型过程中&#xff0c;裸辞与在职学习的利弊及适用人群。裸辞可集中时间快速学习&#xff0c;但经济压力大&#xff1b;在职学习有稳定收入&#xff0c;但时间碎片化&#xff0c;学习周期长。文章建议根据个人经济状况、技能基础和风险承受能力选择路径…...

GLM-OCR在跨境电商中的应用:多语言商品说明书OCR→自动翻译预处理

GLM-OCR在跨境电商中的应用&#xff1a;多语言商品说明书OCR→自动翻译预处理 1. 项目概述与背景 跨境电商卖家经常面临一个共同难题&#xff1a;来自不同国家的商品说明书语言各异&#xff0c;手动翻译不仅耗时耗力&#xff0c;还容易出错。传统OCR工具虽然能识别文字&#…...

Windows下Power Shell快速激活venv虚拟环境的正确姿势(避坑指南)

Windows下Power Shell快速激活venv虚拟环境的正确姿势&#xff08;避坑指南&#xff09; 在Windows平台上使用Python进行开发时&#xff0c;虚拟环境&#xff08;venv&#xff09;是隔离项目依赖的必备工具。然而&#xff0c;许多从Linux/macOS转向Windows的开发者&#xff0c;…...

生物信息学实战指南 | GSEA富集分析从原理到R语言实现

1. GSEA富集分析入门&#xff1a;为什么它比传统方法更强大 第一次接触GSEA&#xff08;Gene Set Enrichment Analysis&#xff09;时&#xff0c;我和大多数初学者一样困惑&#xff1a;明明已经有GO和KEGG这些传统富集分析方法了&#xff0c;为什么还要用GSEA&#xff1f;直到…...

惊艳展示:MedGemma医学影像分析系统,自然语言提问生成专业报告

惊艳展示&#xff1a;MedGemma医学影像分析系统&#xff0c;自然语言提问生成专业报告 1. 引言&#xff1a;当AI能“看懂”医学影像&#xff0c;并“说”出专业见解 想象一下&#xff0c;你手里有一张肺部X光片&#xff0c;但你不是放射科医生。你看着那些黑白影像和复杂的结…...