Flutter自適用高度PageView的實現(xiàn)方案
需求
在 Flutter 中,PageView
是一個非常常用的組件,能夠?qū)崿F(xiàn)多個頁面的滑動切換。然而,默認(rèn)的 PageView
高度是固定的,這在展示不同高度的頁面時,可能會導(dǎo)致不必要的空白或內(nèi)容裁剪問題。為了使 PageView
能夠根據(jù)每個頁面的內(nèi)容高度動態(tài)調(diào)整,我們需要一個自適應(yīng)高度的 PageView
實現(xiàn)。
效果
本方案的 PageView
可以根據(jù)每個頁面內(nèi)容的高度自動調(diào)整,保證每個頁面的內(nèi)容在其實際高度內(nèi)完整顯示,并且在頁面滑動時,使用平滑的過渡效果。具體來說:
- 每個頁面的內(nèi)容高度不同,
PageView
能夠動態(tài)調(diào)整高度。 - 頁面切換時,高度變化平滑,不會造成突兀的視覺效果。
實現(xiàn)思路
1. 測量每個頁面的高度
首先,我們需要為每個頁面添加一個高度測量的機(jī)制,測量頁面內(nèi)容的高度。在 Flutter 中,我們可以通過 GlobalKey
和 RenderBox
獲取每個 Widget
的實際高度。
2. 動態(tài)調(diào)整 PageView 高度
在頁面滑動時,我們需要根據(jù)滑動的進(jìn)度動態(tài)計算當(dāng)前 PageView
的高度。這就需要在 PageView
的滑動過程中實時更新高度,使得高度隨滑動位置逐步過渡。
3. 動態(tài)高度過渡
我們可以使用 AnimatedContainer
來平滑過渡 PageView
的高度,避免切換時高度變化過于突兀。通過監(jiān)聽 PageView
的滑動狀態(tài),實時調(diào)整容器高度。
實現(xiàn)代碼
1. 高度測量組件 HeightMeasureWidget
這個組件負(fù)責(zé)測量每個頁面的高度,并將測量結(jié)果通過回調(diào)傳遞出去。
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. 自適應(yīng)高度的 AutoHeightPageView
這個組件使用了前面創(chuàng)建的 HeightMeasureWidget
來測量每個頁面的高度,然后根據(jù)滑動進(jìn)度調(diào)整高度。
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
該頁面演示了如何使用自適應(yīng)高度的 PageView
,通過內(nèi)容高度的動態(tài)調(diào)整,確保 PageView
始終適應(yīng)當(dāng)前頁面的高度。
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, ), ], ), ), ), ); } }
總結(jié)
通過本方案,我們實現(xiàn)了一個自適應(yīng)高度的 PageView
,它能夠根據(jù)每個頁面的內(nèi)容高度進(jìn)行動態(tài)調(diào)整。該實現(xiàn)依賴于對每個頁面內(nèi)容的測量,并使用 AnimatedContainer
來平滑地過渡高度變化。這樣可以確保頁面切換時,用戶體驗更加自然流暢,避免了內(nèi)容被裁剪或空白區(qū)域的出現(xiàn)。這種自適應(yīng)高度的 PageView
非常適合用于不同頁面內(nèi)容高度不一致的場景。
詳情:github.com/yixiaolunhui/flutter_xy
到此這篇關(guān)于Flutter自適用高度PageView的實現(xiàn)方案的文章就介紹到這了,更多相關(guān)Flutter PageView內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解cesium實現(xiàn)大批量POI點位聚合渲染優(yōu)化方案
這篇文章主要為大家介紹了cesium實現(xiàn)大批量POI點位聚合渲染優(yōu)化方案詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05