当前位置: 首页 > news >正文

Flutter 布局

要点

Flutter 布局的核心机制是 widget。在 Flutter 中,几乎所有东西都是 widget — 甚至布局模型都是 widget。你在 Flutter 应用程序中看到的图像,图标和文本都是 widget。此外不能直接看到的也是 widget,例如用来排列、限制和对齐可见 widget 的行、列和网格。

布局

流程

  1. 选择一个布局Widget
  2. 创建一个可见Widget
  3. 将可见Widget添加到布局Widget
  4. 将布局Widget添加到页面
  5. 运行应用

Center

步骤1: 选择Center Widget


// 步骤4: 一个 Flutter 应用本身就是一个 widget,大多数 widget 都有一个 build() 方法,在应用的 build() 方法中实例化和返回一个 widget 会让它显示出来。
Widget build(BuildContext context) {return const MaterialApp(home: Scaffold(// 步骤3: 通过child属性将Text Widget添加到Center Widget中body: Center(child: Text('Hello World!'), // 创建可见的 Widget),),);
}

所有布局Widget都具有以下任一项:

  • 一个child属性,当布局Widget只包含一个子项,比如Center,Container
  • 一个children属性,当布局Widget包含多个子项,比如Row,Column,ListViewStack

对应 Material 应用,可以使用 Scaffold widget,它提供默认的 banner 背景颜色,还有用于添加抽屉、提示条和底部列表弹窗的 API

Row(列) , Column(行),Container , spacing, Padding, SizedBox, margin,Expanded

Widget build(BuildContext context) {return MaterialApp(title: "Flutter布局学习",home: Scaffold(appBar: AppBar(title: Text("Flutter 布局学习")),body: Column(spacing: 6,children: [Column(spacing: 10,children: [Text("回乡偶书", style: TextStyle(fontSize: 24)),Text("唐.贺知章"),Text("少小离家老大回,乡音无改鬓毛衰。",style: TextStyle(color: Colors.black,fontSize: 16,height: 1.5, // 控制行高),),Text("儿童相见不相识,笑问客从何处来。",style: TextStyle(color: Colors.black, fontSize: 16),),],),Column(spacing: 6,// Text 设置左对齐// 由于Text Widget的大小是自动包裹内容的,// 所以设置Text的Alignment.left不能生效。// 当布局是Column时,可以设置Column的// crossAxisAlignment: CrossAxisAlignment.start。crossAxisAlignment: CrossAxisAlignment.start,children: [Padding(padding: EdgeInsets.fromLTRB(16, 8, 16, 4),child: Text("译文:", textAlign: TextAlign.left),),Padding(padding: EdgeInsets.fromLTRB(16, 8, 16, 4),child: Text("年少时离乡老年才归家,我的乡音虽未改变,但鬓角的毛发却已经疏落。家乡的儿童们看见我,没有一个认识我。他们笑着询问我:你是从哪里来的呀?",),),Padding(padding: EdgeInsets.fromLTRB(16, 8, 8, 4),child: Text("创作背景:"),),Padding(padding: EdgeInsets.fromLTRB(16, 8, 16, 4),child: SizedBox(width: 360,child: Text("贺知章在公元744年(天宝三载),辞去朝廷官职,告老返回故乡越州永兴(今浙江萧山),时已八十六岁,这时,距他中年离乡已经很久了,此诗便作于此时。",),),),],),Row(crossAxisAlignment: CrossAxisAlignment.start,spacing: 10,children: [Padding(padding: EdgeInsets.fromLTRB(16, 0, 0, 0),// Image.asset方法里设置的图片路径是相对于pubspec.yaml文件child: Image.asset('assets/images/layout_01@3x.png',width: 160,alignment: Alignment.center,),),// 设置Text Widget离右侧屏幕距离为16// 1. Expanded占满了父Widget的剩余空间// 2. Container size 包装Text Widget// 3. margin设置控制右边距Expanded(child: Column(spacing: 10,crossAxisAlignment: CrossAxisAlignment.start,children: [Container(// EdgeInsets.only: 仅设置一个方向的间距margin: EdgeInsets.only(right: 16),// L:Left,T:Top,R:Right,B:Bottom 通过英文来记忆4参数// padding: EdgeInsets.fromLTRB(0, 0, 16,0),padding: EdgeInsets.only(right: 16),decoration: BoxDecoration(border: Border.all()),child: Text("问题:请问这首诗表达了作者的什么样的感情?",maxLines: 4,softWrap: true,),),Container(margin: EdgeInsets.only(right: 30),child: Text("如果现在是北京时间早上八点整,我飞往巴黎,到达后巴黎当地时间为早上八点整,请问:我的生命相对延长了吗?",),),Text("答:你把表的电池扣了你是不是就不死了?"),],),),],),],),),);}

2025-05-05 21.54.23.png

名称说明
Column垂直布局,可以包含多个子Widget,子Widget从上往下延伸
Row水平布局,可以包含多个子Widget,子Widget从左往右延伸
Container包含一个子Widget,一般用来包装显示的Widget,在这里设置宽高,内外边距
Padding包含一个子Widget,控制内边距
SizedBox包含一个子Widget,固定大小
Expanded包含一个子Widget,填充父Widget的剩余空间
GridView && ListView

使用 GridView 将 widget 作为二维列表展示。 GridView 提供两个预制的列表,或者你可以自定义网格。当 GridView 检测到内容太长而无法适应渲染盒时,它就会自动支持滚动。

GridView的特点

  • 在网格中使用widget
  • 当列的内容超出渲染容器时,它会自动支持滚动
  • 创建自定义的网格,或者使用 GridView.count 设置列的数量/ GridView.extent设置单元格最大宽度
Widget _buildGrid() => GridView.extent(// 单元格最大宽度,因为子Widget是从上往下延伸,所以主轴是上下,交叉轴是左右,子Widget左右方向的是宽度maxCrossAxisExtent: 150,// 上下左右内边距padding: const EdgeInsets.all(4),// 上下单元格间距mainAxisSpacing: 4,// 左右单元格间距crossAxisSpacing: 4,children: _buildGridTileList(30),
);// 函数支持箭头形式的简写,当函数体只有一行表达式时,可以通过=>简写表示返回表达式的值。
// 从0递增到count-1获取assets/images/pic$i.jpg的图标作为GridView的children
// Generates a list of values.
// Creates a list with [length] positions and fills it with values created by calling [generator] 
// for each index in the range 0 .. length - 1 in increasing order.
List<Widget> _buildGridTileList(int count) =>List.generate(count, (i) => Image.asset('assets/images/pic$i.jpg'));

optimized.gif

ListView是一个和Column相似的Widget,当内容大于自己的渲染框时,就会自动支持滚动

ListView的特点

  • 一个用来组织盒子中列表的专用Column
  • 可以水平或者垂直布局
  • 当检测到空间不足时,会自动支持滚动
  • Column的配置少,使用更容易,且支持滚动
Widget _buildList() {return ListView(children: [_tile('CineArts at the Empire', '85 W Portal Ave', Icons.theaters),_tile('The Castro Theater', '429 Castro St', Icons.theaters),_tile('Alamo Drafthouse Cinema', '2550 Mission St', Icons.theaters),_tile('Roxie Theater', '3117 16th St', Icons.theaters),_tile('United Artists Stonestown Twin','501 Buckingham Way',Icons.theaters,),_tile('AMC Metreon 16', '135 4th St #3000', Icons.theaters),// 分割线const Divider(),_tile('K\'s Kitchen', '757 Monterey Blvd', Icons.restaurant),_tile('Emmy\'s Restaurant', '1923 Ocean Ave', Icons.restaurant),_tile('Chaiya Thai Restaurant', '272 Claremont Blvd', Icons.restaurant),_tile('La Ciccia', '291 30th St', Icons.restaurant),],);}ListTile _tile(String title, String subtitle, IconData icon) {return ListTile(title: Text(title,style: const TextStyle(fontWeight: FontWeight.w500, fontSize: 20),),subtitle: Text(subtitle),leading: Icon(icon, color: Colors.blue[500]),);}

2025-05-06 10.50.56.png

里面每一行都是ListTile,它是Material库中专用的行Widget,它可以很轻松的创建一个包含三行文本以及可选的行前和行尾图标的行。 ListTileCard 或者 ListView 中最常用,但是也可以在别处使用。

Stack

Stack布局用于叠加场景,比如图片上添加文字描述

Stack的特点

  • 用于覆盖另一个Widget – 类似栈:后进(渲染)先出(显示在外层)
  • 子列表中的第一个Widget是基础Widget;后面的子项覆盖在基础Widget的顶部
  • Stack的内容是无法滚动的
  • 可以剪切掉超出渲染框的子项

2025-05-06 11.13.36.png

Card

Material 库中的Card包含相关有价值信息,几乎可以由任何Widget组成,但是通常和ListTile一起使用,Card 只有一个子项,这个子项可以是列,行,列表,网格或者其它支持多个子项的Widget。默认情况下,Card的大小是0x0像素。可以使用SizeBox控制Card的大小

Flutter 中,Card 有轻微的圆角和阴影来使它具有 3D 效果。改变 Cardelevation 属性可以控制阴影效果

Widget _buildCard() {return SizedBox(height: 210,child: Card(child: Column(children: [ListTile(title: const Text('1625 Main Street',style: TextStyle(fontWeight: FontWeight.w500),),subtitle: const Text('My City, CA 99984'),leading: Icon(Icons.restaurant_menu, color: Colors.blue[500]),),const Divider(),ListTile(title: const Text('(408) 555-1212',style: TextStyle(fontWeight: FontWeight.w500),),leading: Icon(Icons.contact_phone, color: Colors.blue[500]),),ListTile(title: const Text('costa@example.com'),leading: Icon(Icons.contact_mail, color: Colors.blue[500]),),],),),);}

2025-05-06 11.21.21.png

一些收获

CrossAxisAlignment(交叉轴) && MainAxisAlignment(主轴)

MainAxisAlignment(主轴)就是与当前子Widget延伸方向一致的轴,而CrossAxisAlignment(交叉轴)就是与当前子Widget延伸方向垂直的轴

比如Column: 子Widget是从上往下延伸的,所以主轴就是垂直方向,交叉轴就是水平方向的。
ColumnMainAxisAlignment 属性用于控制子Widget在主轴(垂直轴)上的对齐方式,ColumnCrossAxisAlignment 属性用于控制子Widget在交叉轴(水平轴)上的对齐方式

当设置为CrossAxisAlignment.start时表示Column中的元素左对齐。

格式化

通过快捷键 ⌥(option) + ⇧(shift) + f 可以快速对代码格式化

内容不可见

Flutter界面会告警提示当前的布局超过多少像素,存在内容不可见的问题

Waiting for another flutter command to release the startup lock

问题: VS Code 创建新的Flutter工程一直卡在Waiting for another flutter command to release the startup lock

方案:

# 执行后关闭VS Code 重新打开再次创建Flutter工程
killall -9 dart

ERR : Proxy failed to establish tunnel (503 Forwarding failure), uri=//pub.flutter-io.cn:443

一般是网络原因,我是终端加了端口转发,然后一直访问不了pub.flutter-io.cn,所以去掉代理

# 去掉代理 + 重新执行 flutter pub get --verbose
export https_proxy=
export http_proxy= 

参考

  1. Waiting for another flutter command to release the startup lock
  2. flutter 设置Text居左无效
  3. Flutter 中的 Column 小部件:全面指南
  4. https://docs.flutter.cn/ui/layout/constraints/
  5. GridView.extent中maxCrossAxisExtent的作用

相关文章:

  • Java 内存区域与内存溢出异常
  • 数据结构 --- 栈
  • AI 数字短视频数字人源码开发实用技巧分享​
  • 19.第二阶段x64游戏实战-vector容器
  • Navicat Premium 17 备份,还原数据库(PostGreSql)
  • 第四节:进程控制
  • cookie/session的关系
  • Python基础学习-Day17
  • 第九章,链路聚合和VRRP
  • 编码器型与解码器型语言模型的比较
  • Github打不开怎么办?
  • IDEA Mysql连接失败,移除JDBC驱动程序中的协议列表
  • python学习记录
  • Science Advances:南京大学基于硅光芯片实现非阿贝尔辫子操作,突破量子逻辑门技术
  • Codeforces Round 1023 (Div. 2) (A-D)
  • huggingface 热门开源TTS模型Dia-1.6B,支持多人对话生成、情感控制~
  • 多模态理论知识
  • 土建施工员考试重点内容总结
  • 网络编程核心技术解析:从Socket基础到实战开发
  • 深入理解分布式锁——以Redis为例
  • 全国首例在沪完成,这项近视治疗手术不到10秒
  • 三大交易所多举措支持科创债再扩容,约160亿证券公司科创债有望近期落地
  • 马上评|从一个细节看今年五一档电影
  • 库里22分赢下抢七大战,火箭10年难破“火勇大战”的魔咒
  • 中小企业数字化转型的破局之道何在?
  • 申活观察|精致精准精细,城市“双面镜”照见怎样的海派活力