Flutter-自适用高度PageView
需求
在 Flutter 中,PageView 是一个非常常用的组件,能够实现多个页面的滑动切换。然而,默认的 PageView 高度是固定的,这在展示不同高度的页面时,可能会导致不必要的空白或内容裁剪问题。为了使 PageView 能够根据每个页面的内容高度动态调整,我们需要一个自适应高度的 PageView 实现。
效果

本方案的 PageView 可以根据每个页面内容的高度自动调整,保证每个页面的内容在其实际高度内完整显示,并且在页面滑动时,使用平滑的过渡效果。具体来说:
- 每个页面的内容高度不同,
PageView能够动态调整高度。 - 页面切换时,高度变化平滑,不会造成突兀的视觉效果。
实现思路
1. 测量每个页面的高度
首先,我们需要为每个页面添加一个高度测量的机制,测量页面内容的高度。在 Flutter 中,我们可以通过 GlobalKey 和 RenderBox 获取每个 Widget 的实际高度。
2. 动态调整 PageView 高度
在页面滑动时,我们需要根据滑动的进度动态计算当前 PageView 的高度。这就需要在 PageView 的滑动过程中实时更新高度,使得高度随滑动位置逐步过渡。
3. 动态高度过渡
我们可以使用 AnimatedContainer 来平滑过渡 PageView 的高度,避免切换时高度变化过于突兀。通过监听 PageView 的滑动状态,实时调整容器高度。
实现代码
1. 高度测量组件 HeightMeasureWidget
这个组件负责测量每个页面的高度,并将测量结果通过回调传递出去。
import 'package:flutter/material.dart';class HeightMeasureWidget extends StatefulWidget {final Widget child;final Function(double height) onHeightChanged;const HeightMeasureWidget({super.key, required this.child, required this.onHeightChanged});HeightMeasureState createState() => HeightMeasureState();
}class HeightMeasureState extends State<HeightMeasureWidget> {final GlobalKey _key = GlobalKey();void initState() {super.initState();WidgetsBinding.instance.addPostFrameCallback((_) {_measureHeight();});}void _measureHeight() {final RenderBox? renderBox =_key.currentContext!.findRenderObject() as RenderBox?;if (renderBox != null) {widget.onHeightChanged(renderBox.size.height);}}Widget build(BuildContext context) {return Container(key: _key,child: widget.child,);}
}
2. 自适应高度的 AutoHeightPageView
这个组件使用了前面创建的 HeightMeasureWidget 来测量每个页面的高度,然后根据滑动进度调整高度。
import 'package:flutter/material.dart';
import 'measure_height_widget.dart';class AutoHeightPageView extends StatefulWidget {final List<Widget> children;final PageController pageController;const AutoHeightPageView({Key? key,required this.children,required this.pageController,}) : super(key: key);AutoHeightPageViewState createState() => AutoHeightPageViewState();
}class AutoHeightPageViewState extends State<AutoHeightPageView> {final List<double> _heights = [];double _currentHeight = 0;void initState() {super.initState();widget.pageController.addListener(_updateHeight);}void _updateHeight() {if (widget.pageController.position.haveDimensions && _heights.isNotEmpty) {double page = widget.pageController.page ?? 0.0;int index = page.floor();int nextIndex = (index + 1) < _heights.length ? index + 1 : index;double percent = page - index;double height =_heights[index] + (_heights[nextIndex] - _heights[index]) * percent;setState(() {_currentHeight = height;});}}Widget build(BuildContext context) {var isMeasureHeight =_heights.length == widget.children.length ? false : true;return Column(children: [Stack(children: [Visibility(visible: isMeasureHeight,child: Stack(children: widget.children.map((e) => HeightMeasureWidget(child: e,onHeightChanged: (height) {_heights.add(height);if (_heights.length == widget.children.length) {setState(() {_currentHeight = _heights[0];});}},)).toList(),),),if (!isMeasureHeight)AnimatedContainer(duration: const Duration(milliseconds: 200),height: _currentHeight,curve: Curves.easeOut,child: PageView(controller: widget.pageController,children: widget.children,),),],)],);}void dispose() {widget.pageController.dispose();super.dispose();}
}
3. 使用示例 AutoHeightPageViewPage
该页面演示了如何使用自适应高度的 PageView,通过内容高度的动态调整,确保 PageView 始终适应当前页面的高度。
import 'package:flutter/material.dart';
import 'package:flutter_xy/r.dart';
import 'package:flutter_xy/xydemo/vp/pageview/auto_height_page_view.dart';class AutoHeightPageViewPage extends StatefulWidget {const AutoHeightPageViewPage({Key? key}) : super(key: key);State<StatefulWidget> createState() => AutoHeightPageViewState();
}class AutoHeightPageViewState extends State<AutoHeightPageViewPage> {final PageController _pageController = PageController();Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('自适用高度PageView'),),body: Container(color: Colors.white,child: SingleChildScrollView(child: Column(children: [AutoHeightPageView(pageController: _pageController,children: [Container(color: Colors.white,child: ListView(shrinkWrap: true,physics: const NeverScrollableScrollPhysics(),children: [Container(color: Colors.red,height: 50,alignment: Alignment.center,child: const Text("第一个界面"),),Container(color: Colors.yellow,height: 50,alignment: Alignment.center,child: const Text("第一个界面"),),Container(color: Colors.blue,height: 50,alignment: Alignment.center,child: const Text("第一个界面"),),],),),Container(color: Colors.green,height: 250,child: const Center(child: Text('第二个界面'))),],),Image.asset(R.vp_content_jpg,width: MediaQuery.of(context).size.width,fit: BoxFit.fill,),],),),),);}
}
总结
通过本方案,我们实现了一个自适应高度的 PageView,它能够根据每个页面的内容高度进行动态调整。该实现依赖于对每个页面内容的测量,并使用 AnimatedContainer 来平滑地过渡高度变化。这样可以确保页面切换时,用户体验更加自然流畅,避免了内容被裁剪或空白区域的出现。这种自适应高度的 PageView 非常适合用于不同页面内容高度不一致的场景。
详情:github.com/yixiaolunhui/flutter_xy
相关文章:
Flutter-自适用高度PageView
需求 在 Flutter 中,PageView 是一个非常常用的组件,能够实现多个页面的滑动切换。然而,默认的 PageView 高度是固定的,这在展示不同高度的页面时,可能会导致不必要的空白或内容裁剪问题。为了使 PageView 能够根据每…...
群晖NAS本地搭建可远程交互的大型语言模型LLM聊天机器人
文章目录 前言1. 拉取相关的Docker镜像2. 运行Ollama 镜像3. 运行Chatbot Ollama镜像4. 本地访问5. 群晖安装Cpolar6. 配置公网地址7. 公网访问8. 固定公网地址 前言 本文主要分享如何在群晖NAS本地部署并运行一个基于大语言模型Llama 2的个人本地聊天机器人并结合内网穿透工具…...
TypeScript 构建工具之 webpack
在实际开发中,直接使用TypeScript 编译器的情况不多。 在项目中,需要使用构建工具对代码进行打包,不可能脱离项目使用TypeScript 编译器单独打包TypeScript 。 那如何将 webpack 和 TypeScript 进行集成? 参考文档: w…...
conda环境下在pycharm中调试scrapy项目
前提条件 已经创建好了conda环境已经安装好了scrapy框架项目初始化完成 编写一个爬虫脚本 import scrapyclass StackOverflowSpider(scrapy.Spider):name stackoverflowstart_urls [http://stackoverflow.com/questions?sortvotes]def parse(self, response):print("…...
contenteditable=“true“的标签限制字数的时候修改光标位置
contenteditable"true"的标签限制字数的时候修改光标位置 有时候input和textarea并不能完全满足ui需求,这个时候我们就用contenteditable"true"来将别的标签修改为可编辑状态,但当我们通过js修改了内容之后光标的位置就是一个问题&…...
51单片机-LED灯蜂鸣器数码管按键DS18B20温度传感器
LDE灯的相关程序 LED灯闪烁 LED流水灯 方法1 方法二: 因为P1口可以直接控制P1^0~P1^7的8个led灯,利用一个8位的二进制数字来进行控制即可。如果要点亮P1^0 只需要给P1口传递 1111 1110即可。 蜂鸣器的使用 什么是蜂鸣器? 蜂鸣器是一种一…...
笔记本一线品牌有哪些
笔记本电脑的一线品牌通常指的是在市场上具有较高市场份额、良好口碑、较强的技术实力和服务能力的品牌。根据目前的信息,笔记本电脑市场的一线品牌主要包括以下几个: 联想 (Lenovo):联想在全球笔记本市场上的占有率较高,其产品线…...
mysql聚合函数和分组
我最近开了几个专栏,诚信互三! > |||《算法专栏》::刷题教程来自网站《代码随想录》。||| > |||《C专栏》::记录我学习C的经历,看完你一定会有收获。||| > |||《Linux专栏》࿱…...
ubuntu20.04+RealSenseD455
ubuntu20.04安装驱动双目相机RealSenseD455 安装环境安装RealSense SDK 2.0ROS包安装启动Realsense摄像头存在的 bugD455标定安装环境 系统:Ubuntu20.04 ROS:Noetic 视觉传感器:Intel RealSense D455 安装RealSense SDK 2.0 该安装有两种方式,一个是用命令安装,另一个是…...
WAF绕过技巧
WAF绕过技巧 WAF(Web Application Firewall)是一种安全系统,旨在监控和控制网络流量,以防止攻击,如SQL 注入、跨站脚本(XSS)和拒绝服务(DoS)。 WAF 可以通过多种方式绕过…...
HarmonyOS应用三之组件生命周期和参数传递
目录: 1、生命周期的执行顺序2、页面数据传递3、图片的读取4、数据的备份和恢复5、轮播图6、页面布局图 1、生命周期的执行顺序 /** Copyright (c) 2023 Huawei Device Co., Ltd.* Licensed under the Apache License, Version 2.0 (the "License");* yo…...
[Qt][Qt 网络][上]详细讲解
目录 0.概述1.UDP Socket1.核心API概览2.回显服务器3.回显客户端 0.概述 要使用Qt中有关网络编程的API,需要添加network模块 1.UDP Socket 1.核心API概览 主要的类有两个:QUdpSocket和QNetworkDatagramQUdpSocket表⽰⼀个UDP的socket⽂件 bind(const …...
读零信任网络:在不可信网络中构建安全系统21读后总结与感想兼导读
1. 基本信息 零信任网络:在不可信网络中构建安全系统 道格巴斯(Doug Barth) 著 人民邮电出版社,2019年8月出版 1.1. 读薄率 书籍总字数252千字,笔记总字数73194字。 读薄率73194252000≈29.5% 这个读薄率是最高的吧&#x…...
Java基础——注释
在开发中注释是必不可少的,帮助我们更好的标记阅读代码,下面介绍几种常用的注释方式。 一、注释种类 1. 单行注释 使用//一行代码来进行注释,只能注释一行内容 2. 多行注释 使用斜杠星号的方式 /*注释多行代码*/,注释多行代…...
Redis未授权访问漏洞利用合集
一、基本信息 靶机:IP:192.168.100.40 攻击机:IP:192.168.100.60 二、漏洞 & 过程 Redis 未授权访问漏洞利用无口令远程登录靶机 靶机 cd redis-4.0.8/src./redis-server ../redis.conf 攻击机 ./redis-cli -h 192.168.100.40 Redis 未授权访问…...
基于asp.net的在线考试系统、基于c#的在线考试管理系统
摘 要 伴随着社会以及科学技术的发展,互联网已经渗透在人们的身边,网络慢慢的变成了人们的生活必不可少的一部分,紧接着网络飞速的发展,管理系统这一名词已不陌生,越来越多的学校、公司等机构都会定制一款属于自己个…...
将 hugo 博客搬迁到服务器
1. 说明 在 Ubuntu 22.04 上使用 root 账号,创建普通账号,并赋予 root 权限。 演示站点:https://woniu336.github.io/ 魔改hugo主题: https://github.com/woniu336/hugo-magic 2. 服务器配置 建立 git 用户 adduser git安装 git sudo apt …...
【Datawhale AI夏令营第四期】 魔搭-大模型应用开发方向笔记 Task04 RAG模型 人话八股文Bakwaan_Buddy项目创空间部署
【Datawhale AI夏令营第四期】 魔搭-大模型应用开发方向笔记 Task04 RAG模型 人话八股文Bakwaan_Buddy项目创空间部署 什么是RAG: 我能把这个过程理解为Kimi.ai每次都能列出的一大堆网页参考资料吗?Kimi学了这些资料以后,根据这里面的信息综…...
CTF密码学小结
感觉没啥好总结的啊 基础的永远是RSA、流密码、哈希、对称密码、古典密码那一套(密码学上过课都会),其他的就是数论的一些技巧 似乎格密码也很流行,以及一些奇奇怪怪的性质利用也很多 1、random设置种子后随机的性质:…...
Vue快速入门(七)——Vue3 状态管理 - Pinia(二)
目录 六、核心概念——Getter 1、基本操作 定义getter 访问getter 2、访问其他 getter 3、向 getter 传递参数 4、访问其他 store 的 getter 使用 setup() 时的用法 使用选项式 API 的用法 使用 setup() 不使用 setup() 七、核心概念——Action 1、基本操作 定义a…...
OpenLayers 可视化之热力图
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 热力图(Heatmap)又叫热点图,是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...
【杂谈】-递归进化:人工智能的自我改进与监管挑战
递归进化:人工智能的自我改进与监管挑战 文章目录 递归进化:人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管?3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...
【2025年】解决Burpsuite抓不到https包的问题
环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...
Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...
第八部分:阶段项目 6:构建 React 前端应用
现在,是时候将你学到的 React 基础知识付诸实践,构建一个简单的前端应用来模拟与后端 API 的交互了。在这个阶段,你可以先使用模拟数据,或者如果你的后端 API(阶段项目 5)已经搭建好,可以直接连…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现指南针功能
指南针功能是许多位置服务应用的基础功能之一。下面我将详细介绍如何在HarmonyOS 5中使用DevEco Studio实现指南针功能。 1. 开发环境准备 确保已安装DevEco Studio 3.1或更高版本确保项目使用的是HarmonyOS 5.0 SDK在项目的module.json5中配置必要的权限 2. 权限配置 在mo…...
规则与人性的天平——由高考迟到事件引发的思考
当那位身着校服的考生在考场关闭1分钟后狂奔而至,他涨红的脸上写满绝望。铁门内秒针划过的弧度,成为改变人生的残酷抛物线。家长声嘶力竭的哀求与考务人员机械的"这是规定",构成当代中国教育最尖锐的隐喻。 一、刚性规则的必要性 …...
客户案例 | 短视频点播企业海外视频加速与成本优化:MediaPackage+Cloudfront 技术重构实践
01技术背景与业务挑战 某短视频点播企业深耕国内用户市场,但其后台应用系统部署于东南亚印尼 IDC 机房。 随着业务规模扩大,传统架构已较难满足当前企业发展的需求,企业面临着三重挑战: ① 业务:国内用户访问海外服…...
【免费数据】2005-2019年我国272个地级市的旅游竞争力多指标数据(33个指标)
旅游业是一个城市的重要产业构成。旅游竞争力是一个城市竞争力的重要构成部分。一个城市的旅游竞争力反映了其在旅游市场竞争中的比较优势。 今日我们分享的是2005-2019年我国272个地级市的旅游竞争力多指标数据!该数据集源自2025年4月发表于《地理学报》的论文成果…...
Python学习(8) ----- Python的类与对象
Python 中的类(Class)与对象(Object)是面向对象编程(OOP)的核心。我们可以通过“类是模板,对象是实例”来理解它们的关系。 🧱 一句话理解: 类就像“图纸”,对…...
