目录
Container
Padding
Align
Center
Offstage
Baseline
Container
Container在Flutter最常用的组件。是一个结合了绘制(painting)、定位(positioning)以及尺寸(sizing)widget的widget。
组成
- Container的组成如下:
- 最里层的是child元素;
- child元素首先会被padding包着;
- 然后添加额外的constraints限制;
- 最后添加margin。
- Container的绘制的过程如下:
- 首先会绘制transform效果;
- 接着绘制decoration;
- 然后绘制child;
- 最后绘制foregroundDecoration。
- Container自身尺寸的调节分两种情况:
- Container在没有子节点(children)的时候,会试图去变得足够大。除非constraints是unbounded限制,在这种情况下,Container会试图去变得足够小。
- 带子节点的Container,会根据子节点尺寸调节自身尺寸,但是Container构造器中如果包含了width、height以及constraints,则会按照构造器中的参数来进行尺寸的调节。
布局行为
- 由于Container组合了一系列的widget,这些widget都有自己的布局行为,因此Container的布局行为有时候是比较复杂的。
- 一般情况下,Container会遵循如下顺序去尝试布局:
- 对齐(alignment);
- 调节自身尺寸适合子节点;
- 采用width、height以及constraints布局;
- 扩展自身去适应父节点;
- 调节自身到足够小。
- 进一步说:
- 如果没有子节点、没有设置width、height以及constraints,并且父节点没有设置unbounded的限制,Container会将自身调整到足够小。
- 如果没有子节点、对齐方式(alignment),但是提供了width、height或者constraints,那么Container会根据自身以及父节点的限制,将自身调节到足够小。
- 如果没有子节点、width、height、constraints以及alignment,但是父节点提供了bounded限制,那么Container会按照父节点的限制,将自身调整到足够大。
- 如果有alignment,父节点提供了unbounded限制,那么Container将会调节自身尺寸来包住child;
- 如果有alignment,并且父节点提供了bounded限制,那么Container会将自身调整的足够大(在父节点的范围内),然后将child根据alignment调整位置;
- 含有child,但是没有width、height、constraints以及alignment,Container会将父节点的constraints传递给child,并且根据child调整自身。
- 另外,margin以及padding属性也会影响到布局
Container({
Key key,
this.alignment,
this.padding,
Color color,
Decoration decoration,
this.foregroundDecoration,
double width,
double height,
BoxConstraints constraints,
this.margin,
this.transform,
this.child,
})
- key:Container唯一标识符,用于查找更新。
- alignment:控制child的对齐方式,如果container或者container父节点尺寸大于child的尺寸,这个属性设置会起作用,有很多种对齐方式。
- padding:decoration内部的空白区域,如果有child的话,child位于padding内部。padding与margin的不同之处在于,padding是包含在content内,而margin则是外部边界,设置点击事件的话,padding区域会响应,而margin区域不会响应。
- color:用来设置container背景色,如果foregroundDecoration设置的话,可能会遮盖color效果。
- decoration:绘制在child后面的装饰,设置了decoration的话,就不能设置color属性,否则会报错,此时应该在decoration中进行颜色的设置。
- foregroundDecoration:绘制在child前面的装饰。
- width:container的宽度,设置为double.infinity可以强制在宽度上撑满,不设置,则根据child和父节点两者一起布局。
- height:container的高度,设置为double.infinity可以强制在高度上撑满。
- constraints:添加到child上额外的约束条件。
- margin:围绕在decoration和child之外的空白区域,不属于内容区域。
- transform:设置container的变换矩阵,类型为Matrix4。
- child:container中的内容widget。
Padding
Padding在Flutter中用的也挺多的,作为一个基础的控件,功能非常单一,给子节点设置padding属性。写过其他端的都了解这个属性,就是设置内边距属性,内边距的空白区域,也是widget的一部分。
布局行为
- Padding的布局分为两种情况:
- 当child为空的时候,会产生一个宽为left+right,高为top+bottom的区域;
- 当child不为空的时候,Padding会将布局约束传递给child,根据设置的padding属性,缩小child的布局尺寸。然后Padding将自己调整到child设置了padding属性的尺寸,在child周围创建空白区域。
const Padding({
Key key,
@required this.padding,
Widget child,
})
- padding:padding的类型为EdgeInsetsGeometry,EdgeInsetsGeometry是EdgeInsets以及EdgeInsetsDirectional的基类。在实际使用中不涉及到国际化,例如适配阿拉伯地区等,一般都是使用EdgeInsets。EdgeInsetsDirectional光看命名就知道跟方向相关,因此它的四个边距不限定上下左右,而是根据方向来定的。
Align
在其他端的开发,Align一般都是当做一个控件的属性,并没有拿出来当做一个单独的控件。Align本身实现的功能并不复杂,设置child的对齐方式,例如居中、居左居右等,并根据child尺寸调节自身尺寸。
布局行为
- Align的布局行为分为两种情况:
- 当widthFactor和heightFactor为null的时候,当其有限制条件的时候,Align会根据限制条件尽量的扩展自己的尺寸,当没有限制条件的时候,会调整到child的尺寸;
- 当widthFactor或者heightFactor不为null的时候,Aligin会根据factor属性,扩展自己的尺寸,例如设置widthFactor为2.0的时候,那么,Align的宽度将会是child的两倍。
Align为什么会有这样的布局行为呢?原因很简单,设置对齐方式的话,如果外层元素尺寸不确定的话,内部的对齐就无法确定。因此,会有宽高因子、根据外层限制扩大到最大尺寸、外层不确定时调整到child尺寸这些行为。
const Align({
Key key,
this.alignment = Alignment.center,
this.widthFactor,
this.heightFactor,
Widget child,
})
- alignment:对齐方式,一般会使用系统默认提供的9种方式,但是并不是说只有这9种,例如如下的定义。系统提供的9种方式只是预先定义好的。
- The top left corner.
static const Alignment topLeft = const Alignment(-1.0, -1.0); - Alignment实际上是包含了两个属性的,其中第一个参数,-1.0是左边对齐,1.0是右边对齐,第二个参数,-1.0是顶部对齐,1.0是底部对齐。根据这个规则,我们也可以自定义我们需要的对齐方式,例如
- 居右高于底部1/4处.
static const Alignment rightHalfBottom = alignment: const Alignment(1.0, 0.5), - widthFactor:宽度因子,如果设置的话,Align的宽度就是child的宽度乘以这个值,不能为负数。
- heightFactor:高度因子,如果设置的话,Align的高度就是child的高度乘以这个值,不能为负数。
Center
继承制Align 并强制 this.alignment = Alignment.center;其他与Align一摸一样。
Offstage
Offstage的作用很简单,通过一个参数,来控制child是否显示,日常使用中也算是比较常用的控件。
布局行为
- Offstage的布局行为完全取决于其offstage参数
- 当offstage为true,当前控件不会被绘制在屏幕上,不会响应点击事件,也不会占用空间;
- 当offstage为false,当前控件则跟平常用的控件一样渲染绘制;
另外,当Offstage不可见的时候,如果child有动画,应该手动停掉,Offstage并不会停掉动画。
Baseline
Baseline这个控件,做过移动端开发的都会了解过,一般文字排版的时候,可能会用到它。它的作用很简单,根据child的baseline,来调整child的位置。例如两个字号不一样的文字,希望底部在一条水平线上,就可以使用这个控件,是一个非常基础的控件。
布局行为
- Baseline控件布局行为分为两种情况:
1.如果child有baseline,则根据child的baseline属性,调整child的位置;
2.如果child没有baseline,则根据child的bottom,来调整child的位置。
const Baseline({
Key key,
@required this.baseline,
@required this.baselineType,
Widget child,
})
- baseline:baseline数值,必须要有,从顶部算。
- baselineType:bseline类型,也是必须要有的,目前有两种类型:
alphabetic:对齐字符底部的水平线;
ideographic:对齐表意字符的水平线。
/*
Container({
Key key,
this.alignment,
//控制child的对齐方式,如果container或者container父节点尺寸大于child的尺寸,
这个属性设置会起作用,有很多种对齐方式。
this.padding,
//decoration内部的空白区域,如果有child的话,child位于padding内部。
padding与margin的不同之处在于,padding是包含在content内,而margin则是外部边界,
设置点击事件的话,padding区域会响应,而margin区域不会响应。
Color color,//用来设置container背景色,如果foregroundDecoration设置的话,可能会遮盖color效果。
Decoration decoration,
//绘制在child后面的装饰,设置了decoration的话,就不能设置color属性,
否则会报错,此时应该在decoration中进行颜色的设置。
this.foregroundDecoration,//绘制在child前面的装饰。
double width,//container的宽度,设置为double.infinity可以强制在宽度上撑满,不设置,则根据child和父节点两者一起布局。
double height,//container的高度,设置为double.infinity可以强制在高度上撑满。
BoxConstraints constraints,//添加到child上额外的约束条件。
this.margin,//围绕在decoration和child之外的空白区域,不属于内容区域。
this.transform,//设置container的变换矩阵,类型为Matrix4。
this.child,
})
const Padding({
Key key,
@required this.padding,
//padding的类型为EdgeInsetsGeometry,EdgeInsetsGeometry是EdgeInsets以及EdgeInsetsDirectional的基类。
在实际使用中不涉及到国际化,例如适配阿拉伯地区等,一般都是使用EdgeInsets。
EdgeInsetsDirectional光看命名就知道跟方向相关,因此它的四个边距不限定上下左右,而是根据方向来定的。
Widget child,
})
const Align({
Key key,
this.alignment = Alignment.center,
this.widthFactor,
this.heightFactor,
Widget child,
})
const Baseline({
Key key,
@required this.baseline,//baseline数值,必须要有,从顶部算。
@required this.baselineType,
//bseline类型,也是必须要有的,目前有两种类型:
alphabetic:对齐字符底部的水平线;
ideographic:对齐表意字符的水平线。
Widget child,
})
*/
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
var _offstage = true;
var _offstageRes = "offstage_off";
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
title: "Flutter Demo",
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
title: Text("Container Padding Align Center Offstage Sample"),
),
body: Column(
children: <Widget>[
new Container(
constraints: new BoxConstraints.expand(
height:
Theme.of(context).textTheme.display1.fontSize * 1.1 + 200.0,
),
decoration: new BoxDecoration(
border: new Border.all(width: 2.0, color: Colors.red),
color: Colors.greenAccent,
borderRadius: new BorderRadius.all(new Radius.circular(20.0)),
image: new DecorationImage(
image: new NetworkImage(
'https://profile.csdnimg.cn/E/8/A/3_chen1234219'),
centerSlice: new Rect.fromLTRB(0.0, 0.0, 5.0, 5.0),
),
),
padding: const EdgeInsets.all(30.0),
alignment: Alignment.center,
child: new Text('Container',
style: Theme.of(context)
.textTheme
.display1
.copyWith(color: Colors.black)),
transform: new Matrix4.rotationZ(-0.05),
),
new Padding(
padding: new EdgeInsets.all(8.0),
child: const Card(child: const Text('Padding')),
),
new Align(
alignment: Alignment.centerLeft,
widthFactor: 4.0,
heightFactor: 5.0,
child: new Text("Align"),
),
new Center(
child: new Text("Center"),
),
Offstage(
offstage: _offstage,
child: Container(alignment:Alignment.center,color: Colors.blue, height: 50.0,child: new Text("Offstage"),),
),
new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Baseline(
baseline: 50.0,
baselineType: TextBaseline.alphabetic,
child: new Text(
'Baseline',
style: new TextStyle(
fontSize: 20.0,
textBaseline: TextBaseline.alphabetic,
),
),
),
new Baseline(
baseline: 50.0,
baselineType: TextBaseline.alphabetic,
child: new Container(
width: 30.0,
height: 30.0,
color: Colors.red,
),
),
],
)
],
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
setState(() {
_offstage = !_offstage;
if(_offstage){
_offstageRes = "offstage_on";
}else{
_offstageRes = "offstage_off";
}
});
},
label: Text('$_offstageRes'),
icon: Icon(Icons.thumb_up),
backgroundColor: Colors.pink,
),
),
);
}
}