Flutter/Dart中如何让按钮间间距占满全部可用屏幕空间
问题描述
当前页面效果如下图所示:
对应实现代码如下:
class MyStatelessWidget extends StatelessWidget { const MyStatelessWidget({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Center( child: Column( mainAxisSize: MainAxisSize.min, children: <Widget>[ const SizedBox(height: 30), ClipRRect( borderRadius: BorderRadius.circular(4), child: Stack( children: <Widget>[ Positioned.fill( child: Container( decoration: const BoxDecoration( gradient: LinearGradient( colors: <Color>[ Color(0xFF0D47A1), Color(0xFF1976D2), Color(0xFF42A5F5), ], ), ), ), ), TextButton( style: TextButton.styleFrom( padding: const EdgeInsets.all(16.0), primary: Colors.white, textStyle: const TextStyle(fontSize: 20), ), onPressed: () { Navigator.push( context, MaterialPageRoute(builder: (context) => const NewGameRoute()), ); }, child: const Text('New Game'), ), ], ), ), const SizedBox(height: 30), ClipRRect( borderRadius: BorderRadius.circular(4), child: Stack( children: <Widget>[ Positioned.fill( child: Container( decoration: const BoxDecoration( gradient: LinearGradient( colors: <Color>[ Color(0xFF0D47A1), Color(0xFF1976D2), Color(0xFF42A5F5), ], ), ), ), ), TextButton( style: TextButton.styleFrom( padding: const EdgeInsets.all(16.0), primary: Colors.white, textStyle: const TextStyle(fontSize: 20), ), onPressed: () { Navigator.push( context, MaterialPageRoute(builder: (context) => const NewGameRoute()), ); }, child: const Text('Continue Game'), ), ], ), ), const SizedBox(height: 300), //300 as example ClipRRect( borderRadius: BorderRadius.circular(4), child: Stack( children: <Widget>[ Positioned.fill( child: Container( decoration: const BoxDecoration( gradient: LinearGradient( colors: <Color>[ Color(0xFF0D47A1), Color(0xFF1976D2), Color(0xFF42A5F5), ], ), ), ), ), TextButton( style: TextButton.styleFrom( padding: const EdgeInsets.all(16.0), primary: Colors.white, textStyle: const TextStyle(fontSize: 20), ), onPressed: () { Navigator.push( context, MaterialPageRoute(builder: (context) => const NewGameRoute()), ); }, child: const Text('Button 3'), ), ], ), ), const SizedBox(height: 30), ClipRRect( borderRadius: BorderRadius.circular(4), child: Stack( children: <Widget>[ Positioned.fill( child: Container( decoration: const BoxDecoration( gradient: LinearGradient( colors: <Color>[ Color(0xFF0D47A1), Color(0xFF1976D2), Color(0xFF42A5F5), ], ), ), ), ), TextButton( style: TextButton.styleFrom( padding: const EdgeInsets.all(16.0), primary: Colors.white, textStyle: const TextStyle(fontSize: 20), ), onPressed: () { Navigator.push( context, MaterialPageRoute(builder: (context) => const NewGameRoute()), ); }, child: const Text('Button 4'), ), ], ), ), ], ), ); } }
当前两组按钮之间的大间距通过如下代码实现:
const SizedBox(height: 300), //300 as example
需求是将该固定间距改为自适应值,让两组按钮之间的间距自动占满二者之间所有剩余可用空间。
补充说明
使用参考方案调整后效果如下,虽然基本符合预期,但间距没有实现最大化,需要进一步调整:
解决方案
间距无法自适应最大化的核心原因有两个:
- 外层
Column设置了mainAxisSize: MainAxisSize.min,该属性会让列布局只占用子组件需要的最小高度,不会占满全屏可用空间,自然没有多余空间可以分配 - 固定高度的
SizedBox写死了间距值,无法自动适配不同屏幕的剩余空间
正确实现步骤
- 把Column的
mainAxisSize属性改为MainAxisSize.max,让列布局占满父组件给到的全部可用高度 - 把两组按钮之间的固定高度
SizedBox替换为Spacer组件,该组件会自动占据Flex布局(Column/Row)中的全部剩余空闲空间,默认flex参数为1,不需要额外传值即可占满所有剩余空间 - 如果外层套了Scaffold,不需要额外加高度约束,Scaffold的body默认会占满全屏高度
修改后的核心代码片段
@override Widget build(BuildContext context) { return Center( child: Column( // 让列布局占满全部可用高度 mainAxisSize: MainAxisSize.max, children: <Widget>[ const SizedBox(height: 30), // 上方两个按钮代码保持不变 // ...(Continue Game按钮代码省略) // 替换固定高度间距为Spacer const Spacer(), // 下方两个按钮代码保持不变 // ...(Button 4按钮代码省略) const SizedBox(height: 30), ], ), ); }
内容的提问来源于stack exchange,提问作者Texter
相关产品推荐
相关产品推荐

