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); }, ), ], ), ) ], ), ); }, ); }, ); }
关键细节说明
- GlobalKey的作用:通过GlobalKey可以获取到组件的
RenderBox,进而拿到组件实际渲染后的高度,这是实现自适应的核心。 - PostFrameCallback:确保在页面渲染完成后再获取高度,避免因为组件还未渲染完成而拿到0值。
- 初始高度处理:第一次渲染时
currentPageHeight为0,此时SizedBox的height设为null,会自动包裹子组件内容,完成初始高度的适配。 - 页面内容动态变化:如果登录/注册页面内部有内容动态变化(比如输入框展开、错误提示显示),可以在页面内部添加
WidgetsBinding.instance.addPostFrameCallback来重新计算高度,或者给页面绑定的GlobalKey触发重新测量。
内容的提问来源于stack exchange,提问作者ololo
相关产品推荐
相关产品推荐

