javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > Flutter PageView

Flutter自适用高度PageView的实现方案

作者:一笑轮回~

在 Flutter 中,PageView 是一个非常常用的组件,能够实现多个页面的滑动切换,这篇文章主要介绍了Flutter-自适用高度PageView,需要的朋友可以参考下

需求

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

效果

本方案的 PageView 可以根据每个页面内容的高度自动调整,保证每个页面的内容在其实际高度内完整显示,并且在页面滑动时,使用平滑的过渡效果。具体来说:

实现思路

1. 测量每个页面的高度

首先,我们需要为每个页面添加一个高度测量的机制,测量页面内容的高度。在 Flutter 中,我们可以通过 GlobalKeyRenderBox 获取每个 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内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文