You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter:如何让Bottom Sheet中的PageView无需固定高度正常工作?

解决BottomSheet中PageView自适应内容高度的问题

要让BottomSheet里的PageView无需固定高度、自适应内容尺寸,核心是动态获取当前页面的实际渲染高度并实时更新容器尺寸,具体实现步骤如下:

实现思路

  • 给登录/注册页面分别绑定GlobalKey,用于获取组件的实际渲染高度
  • 监听PageController的页面切换事件,在页面切换完成后获取当前页面的高度
  • 通过StatefulBuilder的setState更新PageView所在容器的高度

修改后的完整代码

_openAuthenticationSheet() async {
  final loginKey = GlobalKey();
  final signupKey = GlobalKey();
  double currentPageHeight = 0;
  PageController pageController = PageController(initialPage: 0);

  // 监听页面切换,动态更新高度
  pageController.addListener(() {
    final currentPageIndex = pageController.page?.round() ?? 0;
    WidgetsBinding.instance.addPostFrameCallback((_) {
      // 获取当前页面的RenderBox
      final RenderBox? renderBox = currentPageIndex == 0
          ? loginKey.currentContext?.findRenderObject() as RenderBox?
          : signupKey.currentContext?.findRenderObject() as RenderBox?;
      
      if (renderBox != null) {
        final newHeight = renderBox.size.height;
        if (newHeight != currentPageHeight) {
          // 调用StatefulBuilder的setState更新高度
          (context as StateSetter)(() {
            currentPageHeight = newHeight;
          });
        }
      }
    });
  });

  showModalBottomSheet(
    context: context,
    clipBehavior: Clip.antiAlias,
    isScrollControlled: true,
    shape: const RoundedRectangleBorder(
      borderRadius: BorderRadius.only(
        topLeft: Radius.circular(20.0),
        topRight: Radius.circular(20.0),
      ),
    ),
    builder: (BuildContext context) {
      return StatefulBuilder(
        builder: (context, setState) {
          return SingleChildScrollView(
            child: Column(
              children: [
                _buildAuthenticationHeaderIcons(),
                // 用动态高度替换固定值,初始为null时自适应内容
                SizedBox(
                  height: currentPageHeight == 0 ? null : currentPageHeight,
                  child: PageView(
                    physics: const NeverScrollableScrollPhysics(),
                    controller: pageController,
                    children: [
                      LogInScreen(
                        key: loginKey, // 绑定GlobalKey
                        navBarColor: navbarColor,
                        handleSignUp: () {
                          pageController.animateToPage(1,
                              duration: const Duration(milliseconds: 500),
                              curve: Curves.easeInOut);
                        },
                      ),
                      SignUpScreen(
                        key: signupKey, // 绑定GlobalKey
                        navBarColor: navbarColor,
                        handleLogIn: () {
                          pageController.animateToPage(0,
                              duration: const Duration(milliseconds: 500),
                              curve: Curves.easeInOut);
                        },
                      ),
                    ],
                  ),
                )
              ],
            ),
          );
        },
      );
    },
  );
}

关键细节说明

  1. GlobalKey的作用:通过GlobalKey可以获取到组件的RenderBox,进而拿到组件实际渲染后的高度,这是实现自适应的核心。
  2. PostFrameCallback:确保在页面渲染完成后再获取高度,避免因为组件还未渲染完成而拿到0值。
  3. 初始高度处理:第一次渲染时currentPageHeight为0,此时SizedBox的height设为null,会自动包裹子组件内容,完成初始高度的适配。
  4. 页面内容动态变化:如果登录/注册页面内部有内容动态变化(比如输入框展开、错误提示显示),可以在页面内部添加WidgetsBinding.instance.addPostFrameCallback来重新计算高度,或者给页面绑定的GlobalKey触发重新测量。

内容的提问来源于stack exchange,提问作者ololo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 10:18:10