抽取Widget
打开我们上一篇的示例的代码,我们发现main.dart里面有很多Widget,这个时候我们是不是可以抽取一下呢?
- 抽取listView: 右键选中
New->Dart File,创建一个新的listview.dart文件, 输入s就可以快速联想出来有状态和无状态的两种widget的代码块

选中stless回车
class extends StatelessWidget {const ({Key? key}) : super(key: key);@overrideWidget build(BuildContext context) {return Container();}}
extends前面的类型为class ListViewDemo extends StatelessWidget
删除const ({Key? key}) : super(key: key);我们这里暂时用不到。此时这个文件中的代码就成为了
import 'package:flutter/material.dart';import 'model/car.dart';class ListViewDemo extends StatelessWidget {Widget _itemForRow(BuildContext context, int index) {return Container(color: Colors.white,margin: EdgeInsets.all(10),child: Column(children: [Image.network(datas[index].imageUrl!),Text(datas[index].name!)],));}@overrideWidget build(BuildContext context) {return ListView.builder(itemBuilder: _itemForRow,itemCount: datas.length,);}}
然后把main.dart的关于ListView全部剪切到这里,此时主工程的home修改为当前的ListViewDemo()
import 'package:flutter/material.dart';import 'package:hello_flutter/base_widget.dart';import 'package:hello_flutter/listview.dart';void main() => runApp(App());class App extends StatelessWidget {@overrideWidget build(BuildContext context) {return MaterialApp(home: Home(),);}}class Home extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(backgroundColor: Colors.grey,appBar: AppBar(title: Text('flutterDemo'),),body: ListViewDemo(),);}}
- 抽取model:把main.dart文件中的
List<Car> datas数据源放置到当前的car.dart文件中。这样主文件中的代码就比较精简了。 同理,把最开始创建的
MyWidget也抽取出去,这样在main.dart如果想要切换使用的话,只需要修改对应的组件构造方法即可。常用Widget
Text组件: String拼接使用
$```dart import ‘package:flutter/material.dart’;
class TextDemo extends StatelessWidget {
final TextStyle _textStyle = TextStyle(
fontSize: 16.0,
backgroundColor: Colors.red,
);
final String _pre = ‘前缀’;
final String _end = ‘后缀’;
@override
Widget build(BuildContext context) {
return Text(‘$_pre 1. 抽取model:把main.dart文件中的List
运行之后:<br /><br />还可以设置最大行数,以及多余的行用省略号表示```dartText(maxLines: 3, // 最大3行overflow: TextOverflow.ellipsis, // 超过3行后缀省略);

富文本RichText组件:这个RichText组件有一个TextSpan可以嵌套使用,针对不同的文本设置不同的style
@overrideWidget build(BuildContext context) {return RichText(text: TextSpan(children: <TextSpan>[TextSpan(text: '$_pre 1. 抽取model:把main.dart文件中的List<Car> ',style: TextStyle(fontSize: 30,color: Colors.yellow)),TextSpan(text: '$_pre 1. 抽取model:把main.dart文件中的List<Car> ',style: TextStyle(fontSize: 20,color: Colors.red)),TextSpan(text: '$_pre 1. 抽取model:把main.dart文件中的List<Car> ',style: TextStyle(fontSize: 40,color: Colors.purpleAccent)),],));}

Container组件:这个组件在布局的时候经常使用。因为它有一个childen而且会自适应布局。搭配着Row这个组件就可以
无限套娃当然还有上一篇介绍的Columnclass TextDemo extends StatelessWidget {@overrideWidget build(BuildContext context) {return Container(child: Row(children: [Container(color: Colors.red,child: Icon(Icons.add),//padding: EdgeInsets.all(30) , // 内边距和子部件有关系// margin: EdgeInsets.all(20), // 外边距和父部件有关系)],),);}}
这里的
padding是内边距,如果没有设置的话是这样的
打开padding的注释可以清楚的看到是图片的内边距
继续打开margin的注释,这样一对比就能看出,margin是图片的外边距。
Flutter布局之Row
弹性盒子布局:横向Row、纵向Column、折叠Stack。在flutter中Alignment的中心点即为父控件的center
import 'package:flutter/material.dart';class LayoutDemo extends StatelessWidget {@overrideWidget build(BuildContext context) {return Container(child: Text('Layout Demo'),alignment: Alignment(0,0), // [-1,1]);}}

我们研究下搭配着row使用的对齐方式,为了方便观察,给每个
Icon包装了一层Container用来设置颜色
class LayoutDemo extends StatelessWidget {@overrideWidget build(BuildContext context) {return Container(alignment: Alignment(0,0),child: Row(children: [Container(child: Icon(Icons.add, size: 60,), color: Colors.yellow,),Container(child: Icon(Icons.sort, size: 60,), color: Colors.red,),Container(child: Icon(Icons.ac_unit, size: 60,), color: Colors.purpleAccent,),Container(child: Icon(Icons.access_alarm, size: 60,), color: Colors.greenAccent,),],),);}}

修改Alignment(-1,-1)的x坐标:
修改Alignment(-1,-1)的y坐标:
此时修改alignment: Alignment(-1,0)让它的横坐标修改为-1或者1都对这个没有影响。但是修改纵坐标y的话:y = -1时图像跑到了最上面,y = 1时图像跑到了最下面,所以说使用Row布局的时候,修改x的坐标不会产生影响。
Flutter布局之Column
此时修改下布局的方式
import 'package:flutter/material.dart';class LayoutDemo extends StatelessWidget {@overrideWidget build(BuildContext context) {return Container(alignment: Alignment(1,1),child: Column(children: [Container(child: Icon(Icons.add, size: 60,), color: Colors.yellow,),Container(child: Icon(Icons.sort, size: 60,), color: Colors.red,),Container(child: Icon(Icons.ac_unit, size: 60,), color: Colors.purpleAccent,),Container(child: Icon(Icons.access_alarm, size: 60,), color: Colors.greenAccent,),],),);}}


同理,如果搭配着Column来布局的话,此时修改alignment: Alignment(-1,0)让它的纵坐标修改为-1或者1都对这个没有影响。但是修改横坐标x的话:x = -1时图像跑到了最左面,x = 1时图像跑到了最右面,所以说使用Column布局的时候,修改y的坐标不会产生影响。
Flutter布局之Stack
import 'package:flutter/material.dart';class LayoutDemo extends StatelessWidget {@overrideWidget build(BuildContext context) {return Container(alignment: Alignment(0,0),child: Stack(children: [Container(child: Icon(Icons.add, size: 120,), color: Colors.yellow,),Container(child: Icon(Icons.sort, size: 90,), color: Colors.red,),Container(child: Icon(Icons.ac_unit, size: 60,), color: Colors.purpleAccent,),Container(child: Icon(Icons.access_alarm, size: 30,), color: Colors.greenAccent,),],),);}}

stack可以和Positioned搭配使用来布局相对位置
class LayoutDemo extends StatelessWidget {@overrideWidget build(BuildContext context) {return Container(alignment: Alignment(0,0),child: Stack(children: [Container(child: Icon(Icons.clear, size: 120),color: Colors.yellow,),Positioned(child: Container(child: Icon(Icons.sort, size: 60),color: Colors.red,), left: 0,), // 距离父视图左边为0 double像素点Positioned(child: Container(child: Icon(Icons.search, size: 30),color: Colors.blue,), right: 0,) // 距离父视图右边为0],),);}}

主轴和交叉轴
使用以上三种方向布局的时候我们需要知道主轴!主轴属性:居中、开始、结束
主轴方向:
- 横向Row -> 右边
- 纵向Column -> 下
- 多层Stack -> 外
- 主轴添加属性(start/center/end):默认是从左边开始,如果想从右边开始我们可以添加主轴属性
mainAxisAlignment: MainAxisAlignment.end。同理设置start就是左边,center就是中间 ```dart import ‘package:flutter/material.dart’;
class LayoutDemo extends StatelessWidget { @override Widget build(BuildContext context) { return Container( alignment: Alignment(0,0), child: Row( mainAxisAlignment: MainAxisAlignment.end, // 已结束位置 children: [ Container(child: Icon(Icons.add, size: 120,), color: Colors.yellow,), Container(child: Icon(Icons.sort, size: 90,), color: Colors.red,), Container(child: Icon(Icons.ac_unit, size: 60,), color: Colors.purpleAccent,), Container(child: Icon(Icons.access_alarm, size: 30,), color: Colors.greenAccent,), ], ), ); } }
设置主轴方向之后运行效果:<br />2. 主轴添加属性`MainAxisAlignment.spaceBetween`:剩下的空间平均分配到小部件之间。3. 主轴添加属性`MainAxisAlignment.spaceAround`:剩下的空间平均分配到小部件周围。4. 主轴添加属性`MainAxisAlignment.spaceEvenly`:剩下的空间和小部件一起平均分。5. 交叉轴也就是y轴`CrossAxisAlignment`也有属性(start/center/end),除了基本的三个之外还有一个`CrossAxisAlignment.baseline`,使用Text组件的时候可以看的比较明显就是文字底部对齐,一般搭配着`textBaseline `一起使用,不然会报错```dartimport 'package:flutter/material.dart';class LayoutDemo extends StatelessWidget {@overrideWidget build(BuildContext context) {return Container(alignment: Alignment(0,0),child: Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, // 已结束位置crossAxisAlignment: CrossAxisAlignment.baseline,textBaseline: TextBaseline.alphabetic,children: [Container(child: Icon(Icons.add, size: 120,), color: Colors.yellow,),Container(child: Icon(Icons.sort, size: 90,), color: Colors.red,),Container(child: Icon(Icons.ac_unit, size: 60,), color: Colors.purpleAccent,),Container(child: Icon(Icons.access_alarm, size: 30,), color: Colors.greenAccent,),],),);}}
Expanded
使用Expand的小组件会占满当前的主轴方法,在主轴方向不会剩下空隙,当横线布局不够用的时候会自动换行。
import 'package:flutter/material.dart';class LayoutDemo extends StatelessWidget {@overrideWidget build(BuildContext context) {return Container(alignment: Alignment(0,0),child: Row(children: [Expanded(child: Container(child: Icon(Icons.add, size: 120,), color: Colors.yellow,)),Expanded(child: Container(child: Icon(Icons.sort, size: 90,), color: Colors.red,)),Expanded(child: Container(child: Icon(Icons.ac_unit, size: 60,), color: Colors.purpleAccent,)),Expanded(child: Container(child: Icon(Icons.access_alarm, size: 30,), color: Colors.greenAccent,)),],),);}}
AspectRatio宽高比
class LayoutDemo extends StatelessWidget {@overrideWidget build(BuildContext context){return Container(alignment: Alignment(0,0),child: Container(color: Colors.greenAccent,width: 300, // 如果此时设置了高度 那么下面的宽高比设置将会无效child: AspectRatio(aspectRatio: 1/2,),),);}}
�

