Single-child layout widgets
- Align对齐Widget
class AlignDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
// 添加容器背景颜色,便于更加直观的学习布局Widget
color: Colors.yellow,
// 对齐Widget
child: Align(
// 要布局的子Widget
child: Icon(Icons.pets, size: 36, color: Colors.red),
// 对其方式
alignment: Alignment.center,
// 宽度因子,不设置的情况,会尽可能大
// 3表示Align的宽度是子组件宽度的3倍
widthFactor: 3,
// 高度因子,不设置的情况,会尽可能大
// 3表示Align的高度是子组件高度的3倍
heightFactor: 3,
),
);
}
}
- Center表示居中对齐
class CenterDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
// 添加容器背景颜色,便于更加直观的学习布局Widget
color: Colors.yellow,
// 事实上Center组件继承自Align,只是将alignment设置为Alignment.center
child: Center(
// 要布局的子Widget
child: Icon(Icons.pets, size: 36, color: Colors.red),
// 宽度因子,不设置的情况,会尽可能大
// 3表示Align的宽度是子组件宽度的3倍
widthFactor: 3,
// 高度因子,不设置的情况,会尽可能大
// 3表示Align的高度是子组件高度的3倍
heightFactor: 3,
),
);
}
}
- Padding通常用于设置子Widget到父Widget的边距
class PaddingDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
// 添加容器背景颜色,便于更加直观的学习布局Widget
color: Colors.yellow,
// Padding通常用于设置子Widget到父Widget的边距
child: Padding(
child: Text(
"莫听穿林打叶声,何妨吟啸且徐行。竹杖芒鞋轻胜马,谁怕?一蓑烟雨任平生。",
style: TextStyle(color: Colors.redAccent, fontSize: 18),
),
padding: EdgeInsets.all(18),
),
);
}
}
- Container是一个容器
/* 如果你需要一个视图,有背景颜色、图像、有固定的尺寸、需要一个边框、圆角等效果,那么就可以使用Container组件
Container({
this.alignment, // 对齐方式
this.padding, // 容器内补白,属于decoration的装饰范围
Color color, // 背景色
Decoration decoration, // 背景装饰
Decoration foregroundDecoration, // 前景装饰
double width, // 容器的宽度
double height, // 容器的高度
BoxConstraints constraints, // 容器大小的限制条件
this.margin, // 容器外补白,不属于decoration的装饰范围
this.transform, // 变换
this.child,
})
*/
class ContainerDemo1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Container(
// color和decoration是互斥的,实际上,当指定color时,Container内会自动创建一个decoration
color: Color.fromRGBO(3, 3, 255, .5),
width: 100,
height: 100,
child: Icon(Icons.pets, size: 32, color: Colors.white),
),
);
}
}
- Container有一个非常重要的属性
decoration
/*
const BoxDecoration({
this.color, // 颜色,会和Container中的color属性冲突
this.image, // 背景图片
this.border, // 边框,对应类型是Border类型,里面每一个边框使用BorderSide
this.borderRadius, // 圆角半径设置
this.boxShadow, // 阴影效果
this.gradient, // 渐变效果
this.backgroundBlendMode, // 背景混合模式
this.shape = BoxShape.rectangle, // 形变
})
*/
class ContainerDemo2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Container(
// 和decoration属性中的color属性冲突
// color: Color.fromRGBO(3, 3, 255, .5),
width: 150,
height: 150,
child: Icon(Icons.pets, size: 32, color: Colors.white),
decoration: BoxDecoration(
color: Colors.amber,
// 背景颜色
border: Border.all(
color: Colors.redAccent,
width: 3,
style: BorderStyle.solid
),
// 这里也可以使用Border.all统一设置
// top: BorderSide(
// color: Colors.redAccent,
// width: 3,
// style: BorderStyle.solid
// ),
// 这里也可以使用.only分别设置
borderRadius: BorderRadius.circular(20),
// 阴影效果
boxShadow: [
BoxShadow(
offset: Offset(5, 5),
color: Colors.black54,
blurRadius: 5
)
],
// 会和borderRadius冲突
// shape: BoxShape.circle,
// 渐变效果:由绿渐变成红色
gradient: LinearGradient(colors: [Colors.green, Colors.red])
),
),
);
}
}
- 通过
Container+BoxDecoration
来实现圆角图像
// 通过 Container+BoxDecoration 来实现圆角图像
class ContainerDemo3 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Container(
width: 200,
height: 200,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
image: DecorationImage(
image: NetworkImage("https://tva1.sinaimg.cn/large/006y8mN6gy1g7aa03bmfpj3069069mx8.jpg"),
)
),
),
);
}
}
Multi-child layout widgets
Flex、Row、Column
-
Row、Column组件
是对Flex组件
的封装,主要体现在属性direction
上 - 当
direction
的值为Axis.horizontal
的时候,则是Row
,行排布 - 当
direction
的值为Axis.vertical
的时候,则是Column
,列排布 - 先了解
Row、Column组件
的主轴(MainAxis)
和交叉轴(CrossAxis)
的概念
Row、Column组件的主轴(MainAxis)和交叉轴(CrossAxis) - Row
/// Row特点:
/// (1)水平方向尽可能占据比较大的空间
/// (2)水平方向也包裹内容, 那么设置mainAxisSize: MainAxisSize.min
/// (3)垂直方向包裹内容
class RowDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
/**
* Row({
* // 绑定GlobalKey,用于数据传递
Key key,
// 主轴对齐方式,如果mainAxisSize值为MainAxisSize.min,则此属性无意义
mainAxisAlignment,
// 表示Row在主轴(水平)方向占用的空间
mainAxisSize,
// 交叉轴对齐方式
crossAxisAlignment,
// 表示纵轴的对齐方向
verticalDirection,
// 文本方向,默认为系统当前环境的文本方向(如中文、英语都是从左往右,而阿拉伯语是从右往左)
textDirection,
// 基线,只对文本有效
// 只有crossAxisAlignment设置成了baseline,这个属性才生效
textBaseline,
// 子控件数组[]
children,
})
*/
return Row(
/** MainAxisAlignment:
* 如果mainAxisSize值为MainAxisSize.min,则此属性无意义
* - start: 主轴的开始位置挨个摆放元素(默认值)
* - end: 主轴的结束位置挨个摆放元素
* - center: 主轴的中心点对齐
* - spaceBetween: 左右两边的间距为0, 其它元素之间平分间距
* - spaceAround: 左右两边的间距是其它元素之间的间距的一半
* - spaceEvenly: 所有的间距平分空间
*/
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
/** 表示Row在主轴(水平)方向占用的空间
* 默认是MainAxisSize.max,表示尽可能多的占用水平方向的空间,即:无论子widgets实际占用多少水平空间,Row的宽度始终等于水平方向的最大宽度
* MainAxisSize.min表示尽可能少的占用水平空间,当子widgets没有占满水平剩余空间,则Row的实际宽度等于所有子widgets占用的的水平空间
*/
mainAxisSize: MainAxisSize.max,
/** 纵轴的方向
* - up: 起始位置从下往上
* - down: 起始位置从上往下
*/
verticalDirection: VerticalDirection.up,
/** CrossAxisAlignment:
* - Row的高度等于子Widgets中最高的子元素高度
* - 参考系是verticalDirection
*
* - start: 交叉轴的起始位置对齐
* - end: 交叉轴的结束位置对齐
* - center: 中心点对齐(默认值)
* - baseline: 基线对齐(必须有【文本】的时候才起效果)
* - stretch: 让Row占据交叉轴尽可能大的空间,将所有的子Widget交叉轴的高度, 拉伸到最大
*/
crossAxisAlignment: CrossAxisAlignment.baseline,
// 只有crossAxisAlignment设置成了baseline,这个属性才生效
textBaseline: TextBaseline.ideographic,
textDirection: TextDirection.ltr,
children: <Widget>[
// Expanded 来包裹 Container Widget,并且将它的宽度不设置值
Expanded(
/** flex属性
* 弹性系数
* Row会根据弹性系数来决定 子Widget 占据剩下空间的比例
* 分配比例和宽度无关
*/
flex: 1,
child: Container(width: 0, height: 60, color: Colors.red, child: Text(
"Hello",
style: TextStyle(fontSize: 20),
))
),
Expanded(
flex: 2,// 绿色块宽度是红色块的两倍
child: Container(width: 10000, height: 100, color: Colors.green,
child: Text(
"World",
style: TextStyle(fontSize: 30),
))
),
Container(width: 90, height: 80, color: Colors.blue,
child: Text(
"nba",
style: TextStyle(fontSize: 12),
)),
Container(width: 50, height: 120, color: Colors.orange,
child: Text(
"cba",
style: TextStyle(fontSize: 40),
)),
],
);
}
}
- TextBaseLine理解 TextBaseLine理解
-
Column,参数跟Row一样,这里就不一一说明了
/// Column特点:
/// (1)垂直方向尽可能占据比较大的空间
/// (2)垂直方向也包裹内容, 那么设置mainAxisSize: MainAxisSize.min
/// (3)水平方向包裹内容
class ColumnDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
verticalDirection: VerticalDirection.down,
crossAxisAlignment: CrossAxisAlignment.start,
textDirection: TextDirection.ltr,
children: <Widget>[
// Expanded 来包裹 Container Widget,并且将它的宽度不设置值
Expanded(
/** flex属性
* 弹性系数
* Column会根据弹性系数来决定 子Widget 占据剩下空间的比例
* 分配比例和高度无关
*/
flex: 1,
child: Container(width: 30, height: 60000, color: Colors.red)
),
Expanded(
flex: 2,// 绿色块宽度是红色块的两倍
child: Container(width: 100, height: 100, color: Colors.green)
),
Container(width: 90, height: 80, color: Colors.blue),
Container(width: 50, height: 120, color: Colors.orange),
],
);
}
}
Stack
- 在开发中,我们多个组件很有可能需要重叠显示,比如在一张图片上显示文字或者一个按钮等,在Flutter中我们需要使用层叠布局Stack
- 示例代码
/// 有状态改变
class _StackDemo2State extends State<StackDemo2> {
bool _isFavor = false;
@override
Widget build(BuildContext context) {
/**
* Stack默认的大小是包裹内容的
* - alignment: 从什么位置开始排布所有的子Widget
* - fit: expand(很少使用) 将子元素拉伸到尽可能大
* - overflow: 超出部分【显示/隐藏】
*/
return Stack(
children: <Widget>[
Image.asset("assets/images/xuebao.png"),
Positioned(
left: 0,
right: 0,
bottom: 0,
child: Container(
// 内边距
padding: EdgeInsets.symmetric(horizontal: 8),
color: Color.fromARGB(150, 0, 0, 0),
child: Row(
// 左右两边的间距为0, 其它元素之间平分间距
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
"进击的巨人挺不错的",
style: TextStyle(fontSize: 20, color: Colors.white),
),
IconButton(
icon: Icon(
Icons.favorite,
color: _isFavor? Colors.red : Colors.white,
),
onPressed: () {
setState(() {
_isFavor = !_isFavor;
});
},
)
],
),
),
)
],
);
}
}
/// 无状态改变
class StackDemo1 extends StatelessWidget {
const StackDemo1({
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
/**
* Stack默认的大小是包裹内容的
* - alignment: 从什么位置开始排布所有的子Widget
* - fit: expand(很少使用) 将子元素拉伸到尽可能大
* - overflow: 超出部分【显示/隐藏】
*/
return Stack(
alignment: AlignmentDirectional.bottomCenter,
// fit: StackFit.expand,
// overflow: Overflow.visible,
children: <Widget>[
Image.asset(
"assets/images/xuebao.png",
// width: 300,
fit: BoxFit.fill,
),
// Positioned: 设置子元素的绝对定位
Positioned(
// 距离父容器左边0像素
left: 0,
bottom: 0,
right: 0,
child: Container(
width: 150,
height: 50,
color: Color.fromARGB(150, 0, 0, 0),
)
),
// Positioned: 设置子元素的绝对定位
Positioned(
// 距离父容器右边5像素
right: 5,
bottom: 5,
child: Text(
"进击的巨人",
style: TextStyle(fontSize: 30, color: Colors.yellow),
)
)
]
);
}
}
网友评论