简单效果实现
在页面中垂直水平居中
使用Center Widget
Center widget可以使其子widget在父widget中居中显示。这是实现居中最简单的方法:
使用Column和MainAxisAlignment
当你有多个widget需要垂直居中时,可以使用Column结合MainAxisAlignment.center:
使用Row和CrossAxisAlignment
对于需要水平居中的情况,可以使用Row结合CrossAxisAlignment.center:
结合Container使用
如果你想要更多的控制,比如设置页面的大小或背景色,可以将Center、Column或Row放在Container中:
使用Align Widget
Align widget也可以实现居中效果,通过设置其alignment属性:
使用Scaffold和Center
在实际应用中,页面通常包含在Scaffold中,你可以这样来居中内容:
布局技巧
column中让子元素撑满
可以使用Spacer填充,实现flex:1 的效果
Container 设置最低高度,内容会撑开最小高度
通过设置 constraints 来为 Container 定义一个最小高度,同时让其高度根据内容自适应:
Container(
constraints: BoxConstraints(
minHeight: 100.0, // 设置最低高度
),
padding: EdgeInsets.all(16.0), // 可选:为内容添加内边距
child: Text(
'这是一个内容自适应高度的 Container。',
style: TextStyle(fontSize: 16.0),
),
),
状态栏沉浸式且背景与顶部的header融为一体
banner固定不跟随滑动
import 'package:flutter/services.dart';
import 'package:flutter_app/common.dart';
import 'package:get/get.dart';
import 'package:flutter/material.dart';
class AboutPage extends GetView {
Widget build(BuildContext context) {
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.dark);
return Scaffold(
body: AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle.dark,
child: Stack(
children: [
Container(
width: double.infinity,
height: 400,
color: BaseColor.errorColor,
child: Text('data2'),
),
SafeArea(
child: SingleChildScrollView(
child: Container(
width: double.infinity,
padding: const EdgeInsets.only(top: 20),
child: Column(children: [
Text('data'),
SizedBox(
height: 250,
),
Text('data'),
SizedBox(
height: 250,
),
Text('data'),
SizedBox(
height: 250,
),
Text('data'),
SizedBox(
height: 250,
)
])
)
),
),
]
),)
);
}
}
跟随滚动条滑动版本
Widget _buildBannerBg() {
return Container(
width: double.infinity,
height: 310.h,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(ImgPath.home.bannerBg),
fit: BoxFit.fitWidth,
)
),
child: SafeArea(child: Text('2998')),
);
}
Widget _buildView() {
return AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarIconBrightness: Brightness.light,
statusBarBrightness: Brightness.light,
),
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
_buildBannerBg(),
XTextWidget.h1('text'),
XTextWidget.h1('text'),
XTextWidget.h1('text'),
SizedBox(height: 100.h,),
XTextWidget.h1('text'),
SizedBox(height: 100.h,),
XTextWidget.h1('text'),
SizedBox(height: 100.h,),
XTextWidget.h1('text'),
SizedBox(height: 100.h,),
XTextWidget.h1('text'),
SizedBox(height: 100.h,),
// Container(
// width: double.infinity,
// height: 300,
// color: Colors.yellow,
// )
],
),
),
);
}
Widget build(BuildContext context) {
return GetBuilder<HomeLogic>(builder: (controller) {
return Scaffold(
// 让内容延伸到状态栏下方
extendBodyBehindAppBar: true,
body: _buildView()
);
});
}
stickyFooter布局
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: 'Layout Demos',
theme: ThemeData(primarySwatch: Colors.blue),
home: DemoListPage(),
);
}
}
class DemoListPage extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('布局方案Demo')),
body: ListView(
children: [
ListTile(
title: Text('方案1: Expanded + SingleChildScrollView'),
subtitle: Text('最简单直接的方案,推荐使用'),
onTap: () => Navigator.push(
context,
MaterialPageRoute(builder: (context) => Demo1Page()),
),
),
ListTile(
title: Text('方案2: Flexible + LayoutBuilder'),
subtitle: Text('动态计算空间,更精细控制'),
onTap: () => Navigator.push(
context,
MaterialPageRoute(builder: (context) => Demo2Page()),
),
),
ListTile(
title: Text('方案3: SafeArea + 分区布局'),
subtitle: Text('明确分区,适合复杂界面'),
onTap: () => Navigator.push(
context,
MaterialPageRoute(builder: (context) => Demo3Page()),
),
),
],
),
);
}
}
// ===========================================
// 方案1: Expanded + SingleChildScrollView
// ===========================================
class Demo1Page extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('方案1: Expanded + ScrollView')),
resizeToAvoidBottomInset: false,
body: Column(
children: [
// 上半部分:可滚动内容区域
Expanded(
child: SingleChildScrollView(
padding: EdgeInsets.all(16),
child: Column(
children: [
// Logo区域
Container(
width: 120,
height: 120,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(60),
),
child: Icon(Icons.person, size: 60, color: Colors.white),
),
SizedBox(height: 30),
// 卡片区域
Container(
width: double.infinity,
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.2),
spreadRadius: 2,
blurRadius: 8,
offset: Offset(0, 2),
),
],
),
child: Column(
children: [
Text(
'欢迎登录',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 8),
Text(
'更好的服务体验',
style: TextStyle(
fontSize: 14,
color: Colors.grey[600],
),
),
SizedBox(height: 20),
// 输入框
TextField(
decoration: InputDecoration(
labelText: '手机号码',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.phone),
),
),
SizedBox(height: 16),
// 协议复选框
Row(
children: [
Checkbox(value: true, onChanged: (v) {}),
Expanded(
child: Text(
'我已阅读并同意《用户协议》和《隐私政策》',
style: TextStyle(fontSize: 12),
),
),
],
),
SizedBox(height: 16),
// 登录按钮
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {},
child: Text('获取验证码'),
style: ElevatedButton.styleFrom(
padding: EdgeInsets.symmetric(vertical: 12),
),
),
),
],
),
),
SizedBox(height: 20), // 底部缓冲空间
],
),
),
),
// 下半部分:固定在底部的虚拟键盘
_buildVirtualKeyboard(),
],
),
);
}
}
// ===========================================
// 方案2: Flexible + LayoutBuilder
// ===========================================
class Demo2Page extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('方案2: Flexible + LayoutBuilder')),
resizeToAvoidBottomInset: false,
body: Column(
children: [
// 上半部分:使用Flexible让它占用剩余空间
Flexible(
child: LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: constraints.maxHeight,
),
child: IntrinsicHeight(
child: Column(
children: [
SizedBox(height: 20),
// Logo
Container(
width: 100,
height: 100,
decoration: BoxDecoration(
color: Colors.green,
shape: BoxShape.circle,
),
child: Icon(Icons.lock, size: 50, color: Colors.white),
),
SizedBox(height: 30),
// 简化的登录卡片
Container(
margin: EdgeInsets.symmetric(horizontal: 20),
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.grey[50],
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.grey[300]!),
),
child: Column(
children: [
Text('方案2演示',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600)),
SizedBox(height: 12),
TextField(
decoration: InputDecoration(
labelText: '用户名',
isDense: true,
border: OutlineInputBorder(),
),
),
SizedBox(height: 12),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {},
child: Text('登录'),
),
),
],
),
),
// Spacer推动内容向上,剩余空间填充
Spacer(),
],
),
),
),
);
},
),
),
// 虚拟键盘固定在底部
_buildVirtualKeyboard(),
],
),
);
}
}
// ===========================================
// 方案3: SafeArea + 分区布局
// ===========================================
class Demo3Page extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('方案3: SafeArea + 分区布局')),
resizeToAvoidBottomInset: false,
body: SafeArea(
child: Column(
children: [
// 主要内容区域
Expanded(
child: Container(
width: double.infinity,
color: Colors.grey[50],
child: SingleChildScrollView(
padding: EdgeInsets.all(16),
child: Column(
children: [
// Logo区域
Container(
width: 80,
height: 80,
decoration: BoxDecoration(
color: Colors.orange,
borderRadius: BorderRadius.circular(12),
),
child: Icon(Icons.apps, size: 40, color: Colors.white),
),
SizedBox(height: 20),
// 内容卡片
Card(
elevation: 4,
child: Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'方案3特点',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 8),
Text('• 使用SafeArea避免刘海屏问题'),
Text('• 明确的视觉分区'),
Text('• 适合复杂界面布局'),
SizedBox(height: 16),
TextField(
decoration: InputDecoration(
labelText: '输入内容',
border: OutlineInputBorder(),
),
),
],
),
),
),
SizedBox(height: 20),
],
),
),
),
),
// 分割线
Container(
height: 1,
color: Colors.grey[300],
),
// 固定在底部的虚拟键盘区域
Container(
color: Colors.white,
child: _buildVirtualKeyboard(),
),
],
),
),
);
}
}
// ===========================================
// footer模拟虚拟键盘
// ===========================================
Widget _buildVirtualKeyboard() {
return Container(
width: double.infinity,
height: 200,
color: Colors.red,
child: Text('footer')
);
}