本期周记里主要记录使用 Flutter 开发中布局 Widget 相关的知识。
1.Flutter 中有哪些布局 Widget
所谓布局 widget 即对齐或限制可见 widget 的方式,类似于 Android 原生开发中的 LinearLayout(线性布局)、RelativeLayout(相对布局)等。
Flutter 的布局 Widget 可以分成两类:
- Single-child layout widgets(只有一个子元素)
- Multi-child layout widgets(可以包含多个子元素)
Flutter 中所有的布局 Widget :
2.如何将可见 widget 添加到布局 widget
这个有点类似于 Android 原生开发中,将一个 View(或者 ViewGroup)添加到另一个 View(或者 ViewGroup)中。
在 Flutter 中,所有布局 widgets 都具有以下任一项:
-
一个 child 属性,如果它们只包含一个子项 —— 例如 Center 和 Container。
-
一个 children 属性,如果它们包含多个子项 —— 例如 Row、Column、ListView 和 Stack。
///Container 拥有一个 child 属性,所以我们可以为 Container 添加一个子元素,
///该子元素又可以包含自己的子元素,以此类推...
Container(
padding: EdgeInsets.all(20),
//在 Container 中通过 child 添加一个 Row Widget
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
//在 Row 种通过 children 添加多个 Icon Widget
children: <Widget>[
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.black),
Icon(Icons.star, color: Colors.black),
],
),
)
3.State 的子类通常以下划线开头进行命名,表示它们的实现细节是私有的。如 Flutter 官方 Demo 工程里:
lass MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
/// _MyHomePageState 是 State 的子类
///
/// 命名的时候以下划线开头表示私有
class _MyHomePageState extends State<MyHomePage> {
......
}
4.为了最大限度地减少高度嵌套的布局代码可能导致的视觉混乱,可以在变量和函数中实现 UI 的各个部分。
比如我想实现下图中红色框起来的 5 颗星星:
它的 widget 树形图如下:
//实现一个水平排列的 5 颗星星,并将它赋值给 starts,提供给其他 Widget 调用
var stars = Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.black),
Icon(Icons.star, color: Colors.black),
],
);
final ratings = Container(
padding: EdgeInsets.all(20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
//直接调用我们定义好的一个 widget
stars,
Text(
'170 Reviews',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w800,
fontFamily: 'Roboto',
letterSpacing: 0.5,
fontSize: 20,
),
),
],
),
);
5.Flutter 中 MainAxisAlignment 和 CrossAxisAlignment
推荐阅读:Flutter中MainAxisAlignment和CrossAxisAlignment详解
6.DefaultTextStyle.merge()
//首先实现一个通用的 Style,并将它赋值给 descTextStyle
static var descTextStyle = TextStyle(
color: Colors.black,
fontWeight: FontWeight.w800,
fontFamily: 'Roboto',
letterSpacing: 0.5,
fontSize: 18,
height: 2,
);
// DefaultTextStyle.merge() 允许创建一个默认的文本样式,该文本样式由它的子元素和所有后续子元素继承。
// 也就是说 DefaultTextStyle.merge() 括号的里所有 Text Widget 的样式都统一为 descTextStyle。
final iconList = DefaultTextStyle.merge(
style: descTextStyle,
child: Container(
padding: EdgeInsets.all(20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Column(
children: [
Icon(Icons.kitchen, color: Colors.green[500]),
Text('PREP:'),
Text('25 min'),
],
),
Column(
children: [
Icon(Icons.timer, color: Colors.green[500]),
Text('COOK:'),
Text('1 hr'),
],
),
Column(
children: [
Icon(Icons.restaurant, color: Colors.green[500]),
Text('FEEDS:'),
Text('4-6'),
],
),
],
),
),
);
7.如何让子元素紧密组合在一起
比如像下图的星星一样,紧挨在一起:
方法:将其 mainAxisSize 设置为 MainAxisSize.min
Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.black),
Icon(Icons.star, color: Colors.black),
],
)