本文介绍如何在Flutter中实现自适应高度的PageView组件。通过GlobalKey和RenderBox测量页面实际高度,结合AnimatedContainer实现滑动过程中的高度平滑过渡,解决固定高度导致的空白或内容裁剪问题,提升多页面内容高度不一致时的用户体验。
需求
在 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});
@override
HeightMeasureState createState() => HeightMeasureState();
}
class HeightMeasureState extends State<HeightMeasureWidget> {
final GlobalKey _key = GlobalKey();
@override
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);
}
}
@override
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);
@override
AutoHeightPageViewState createState() => AutoHeightPageViewState();
}
class AutoHeightPageViewState extends State<AutoHeightPageView> {
final List<double> _heights = [];
double _currentHeight = 0;
@override
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;
});
}
}
@override
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,
),
),
],
)
],
);
}
@override
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);
@override
State<StatefulWidget> createState() => AutoHeightPageViewState();
}
class AutoHeightPageViewState extends State<AutoHeightPageViewPage> {
final PageController _pageController = PageController();
@override
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内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!