说明:在介绍Widget的出后可能会涉及到一些属性,例如 Color
, EdgeInsets
等等。我会在其中穿插的说明,以后遇到这样的问题就不会再次说明。
Container
:一个拥有绘制,定位,调整大小的widget。
Container
在使用的时候一般不会直接使用其作为容器组件,通常需要有一个父控件。例如:Center
, Padding
, Colunm
, Row
, Scaffold
等等。
下面是Dart中Container的属性参数
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,
})
Object -> Diagnosticable -> DiagnosticableTree -> Widget -> StatelessWidget Container
color这个属性在大多数的Widget中都是可以设置的,表示的就是颜色的意思,无论是组件的背景色还是文字的颜色,都是需要用到color属性。但是这里如果要和color属性设置值的话,不会像在前端中一样设置字符串(例如red
)或者16进制(例如#FFF
)又或者是rgba这样的形式,需要转变一下思维。在Flutter中,这些常用颜色值以及用一个对象保存下来了,那就是Colors
。所以我穿插的来讲讲Colors
这个对象,看看他的用法。如果foregroundDecoration
设置的话,可能会遮盖color效果。
第一种使用方法就是直接调用Colors
这个对象,我们可以看到会有提示,提示我们有哪些值
例如上图中的black的值就有好几种。但是我们并不能确定其中的12,26,38这些是什么。其实这些是颜色的透明度(Alpha Or Opacity)
第二种就是使用Color属性自己构建颜色,这里有三种表示方式。下面我们使用这三种方式来表示一个完全不透明的白色
0xFFFFFFFF
。或许你没有接触过这种表示方式,更多的是使用#FFF
或者#FFFFFF
的形式表示。这种事ARGB的颜色表示形式,前面的A表示的就是透明度(Alpha Or Opacity),后面的就不用多说了。那前面的A是使用的FF,那是怎么算的哪?简单说明一下。透明度分为256阶(0-255),计算机上面使用16进制表示为( 00 -ff )。透明就是0阶,完全不透明就是255阶。加入透明度是50%,那就是256阶的一半。256 / 2 = 128
,所以,你以为就是128了么,错了,因为256阶是从0开始的而不是从1开始的,所以还需要减一,就是128 - 1 = 127
阶。那127在用16进制表示就是7F
。关于10进制与16进制的转行可以前往在线进制转换。Colors中提供的颜色值就是这种方式写的。
Color.formARGB()
,接收四个参数,A,R,G,B,都是int
整型的数字。取值范围都是[0, 255]。第一个A
就是上面说到的透明度。
double
类型的。取值范围是[0.0, 1.0]。
这就是Flutter中颜色的集中设置方法。
顾名思义,就是设置他的子元素,可以设置也可以不设置,如果不设置,前面也已经说了结果了。
这个属性是可以设置子元素在Container容器中的对齐方式,值包含以下几种
上面的固定值不做过多说明,来谈谈lerp
这个方法。
Alignment.lerp(a, b, c)
。这个方法相当于是区间取值,方法接收三个参数,前两个就是Alignment
的固定的取值,比如说Alignment.center
,第三个是一个double
类型的数值,取值范围是[0.0, 1.0]。如果值是0.0,那么取a
值,如果是1.0,那么取b
值。
上面说到了lerp
方法,不是那几个固定的值那么她是怎么取值的呢?其实就是取坐标中的点。附上一个图,在举个例子你就明白了
Alignment.topLeft 等价于 Alignment(-1.0, -1.0)。
需要注意的是Alignment
直接使用的话,两个参数的取值范围是[-1.0, 1.0]。
下面是App中的源码
import 'package:flutter/material.dart';
void main() => runApp(AlignmentInfo());
class AlignmentInfo extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _AlignmentInfo();
}
}
class _AlignmentInfo extends State<AlignmentInfo> {
Object position = Alignment.center;
double _X = 0.0;
double _Y = 0.0;
@override
Widget build(BuildContext context) {
return Center(
child: Column(
children: <Widget>[
Container(
width: 100,
height: 100,
alignment: position,
margin: EdgeInsets.all(10),
color: Colors.blue,
child: Text('踏浪', style: TextStyle(
color: Colors.white,
fontSize: 20
)),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
RaisedButton(
child: Text('topLeft'),
onPressed: () => setState(() {
this.position = Alignment.topLeft;
this._X = -1.0;
this._Y = -1.0;
}),
),
RaisedButton(
child: Text('topCenter'),
onPressed: () => setState(() {
this.position = Alignment.topCenter;
this._X = 0.0;
this._Y = -1.0;
}),
),
RaisedButton(
child: Text('topRight'),
onPressed: () => setState(() {
this.position = Alignment.topRight;
this._X = 1.0;
this._Y = -1.0;
}),
)
]
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
RaisedButton(
child: Text('centerLeft'),
onPressed: () => setState(() {
this.position = Alignment.centerLeft;
this._X = -1.0;
this._Y = 0.0;
}),
),
RaisedButton(
child: Text('center'),
onPressed: () => setState(() {
this.position = Alignment.center;
this._X = 0.0;
this._Y = 0.0;
}),
),
RaisedButton(
child: Text('centerRight'),
onPressed: () => setState(() {
this.position = Alignment.centerRight;
this._X = 1.0;
this._Y = 0.0;
}),
)
]
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
RaisedButton(
child: Text('bottomLeft'),
onPressed: () => setState(() {
this.position = Alignment.bottomLeft;
this._X = -1.0;
this._Y = 1.0;
}),
),
RaisedButton(
child: Text('bottomCenter'),
onPressed: () => setState(() {
this.position = Alignment.bottomCenter;
this._X = 0.0;
this._Y = 1.0;
}),
),
RaisedButton(
child: Text('bottomRight'),
onPressed: () => setState(() {
this.position = Alignment.bottomRight;
this._X = 1.0;
this._Y = 1.0;
}),
)
]
),
Container(margin: EdgeInsets.all(10)),
Text('Alignment X 的坐标'),
Container(
margin: EdgeInsets.all(10),
child: Slider(
value: _X,
min: -1.0,
max: 1.0,
onChanged: (double value) {
this.setState(() {
this._X = value;
this.position = Alignment(value, _Y);
});
},
),
),
Text('Alignment Y 的坐标'),
Container(
margin: EdgeInsets.all(10),
child: Slider(
value: _Y,
min: -1.0,
max: 1.0,
onChanged: (double value) {
this.setState(() {
this._Y = value;
this.position = Alignment(_X, value);
});
},
),
)
],
),
);
}
}
constraints
可以对Container元素设置最大最小宽高,使用的是BoxConstraint
这个对象
上图中的四个属性就是分别设置最大最小宽高,看属性名字就可以知道,不多说
在前端中这两个属性可是用的最多的两个属性了。padding
是设置元素的内边距,margin
是设置元素的外边距。以一个矩形盒子为例,四条边框为边界,边框以外的是外边距,边框以内的是内边距。
不同于前端的是,Flutter中添加边距需要使用到EdgeInsets
对象。他有如下几个使用方法
参数接收一个number
类型的值,设置为四周。比如margin: EdgeInsets.all(10.0)
就是给元素设置一个10.0的外间距。
这个可以分别设置水平方向与垂直方向上面的间距
margin: EdgeInsets.symmetric(
vertical: 20,
horizontal: 0
)
上面的代码中就是设置垂直方向上下间距是20,水平方向上面是0
接收四个参数,分别设置L(left), T(top), R(right), B(bottom)的间距
设置四个方向上面哪一个不是0,换句话说,没有设置的就是0
margin: EdgeInsets.only(
left: 10,
top: 20
)
```
上面的代码中,就是设置元素左,上的间距是10,20,而没有设置的右,下的间距都是0
**padding与margin的用法是一样的**
## width 与 height
这两个属性就不多说了,设置宽高的两个属性,值是`number`
## transform
`transform`在CSS3中使用的也是非常多的,也包含位移,旋转,缩放等功能。但是使用方法也是和CSS3中略有不同。CSS3中不仅支持关键词还支持`Matrix`矩阵,而Flutter中一般就使用`Matrix4`。
![transform](https://pic-go-1253455210.cos.ap-chengdu.myqcloud.com/blog/transform-flutter.gif)
属性太多,就不一个一个介绍了,不过大部分的值的参数都是`number`类型的值。
更多的属性以及关于矩阵的介绍可以查看[https://juejin.im/post/5be2fd9e6fb9a04a0e2cace0](https://juejin.im/post/5be2fd9e6fb9a04a0e2cace0)。在这里感谢掘金大佬提供的线索。
## decoration
`decoration`是修饰,装饰的意思,所以,这个属性也是对容器的一个修饰装饰的属性。比如背景图,边框等等这些就是修饰。
`decoration`可以使用以下几种,分别介绍一下一下几种修饰的使用方法
- BoxDecoration
- FlutterLogoDecoration
- ShapeDecoration
- UnderlineTabIndicator
### BoxDecoration
BoxDecoration 可以设置一下几种属性
```dart
const BoxDecoration({
this.color, // 设置元素背景色
this.image, // 设置元素背景图
this.border,
this.borderRadius,
this.boxShadow,
this.gradient,
this.backgroundBlendMode,
this.shape = BoxShape.rectangle,
})
设置背景颜色
有一点需要注意的地方,那就是如果你给元素设置了修饰属性,那么你就不能给元素设置color属性了,因为decoration
属性中也是可以设置背景颜色的。
设置背景图片,使用的类是DecorationImage
。这个图片会出现在背景色和渐变上层。通常使用NetworkImage
(网络图片)和AssetImage
(本地图片)。
image: DecorationImage(
image: NetworkImage('https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=324769017,4079415235&fm=26&gp=0.jpg')
)
再来看看DecorationImage
可以设置的属性
const DecorationImage({
@required this.image,
this.colorFilter,
this.fit,
this.alignment = Alignment.center,
this.centerSlice,
this.repeat = ImageRepeat.noRepeat,
this.matchTextDirection = false,
})
唯一要求的就是image
这个属性,而image
属性如何设置值上面已经提到了。那下面几个属性呢?
colorFilter
这个属性主要是对图片做处理,比如高亮,改变饱和度等等,这个属性用的不多。使用的话就是ColorFilter
这个对象,有很多个值,有兴趣的可以自己试一试。
image: DecorationImage(
image: NetworkImage('https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=324769017,4079415235&fm=26&gp=0.jpg'),
colorFilter: ColorFilter.mode(Colors.red, BlendMode.screen)
)
还可能用到的属性就是fit
属性。这个有点像CSS3中的background-size
属性,可以设置BoxFit.cover
,用到的类就是BoxFit
。其他的属性就不多说,基本使用默认的值就可以。
border
设置边框,用到的就是Border
这个类
border: Border.all(
color: Colors.black,
width: 10
)
你可以使用Flutter给我们封装好的方法比如Border.all
,也可以使用Border设置每一个边
border: Border(
left: BorderSide(
color: Colors.red,
width: 1,
style: BorderStyle.solid
),
// other side
),
上面的BorderSide
,BorderStyle
都是Border中的分类。
设置容器的圆角
borderRadius: BorderRadius.all(Radius.circular(50))
你还可以使用BorderRadius.horizontal
,BorderRadius.vertical
,BorderRadius.only
来设置那个角是圆角。
这里关于BoxDecoration
的见到介绍就到这里对了,如果你想了解gradient
以及更多的其他属性,可以查看简书Flutter之BoxDecoration用法详解,感谢huoshe2019提供的优质文章。
FlutterLogoDecoration
在盒子修饰中用的不多,更多的是用在Logo的修饰中。而且,如果你一使用这个属性,那么就会出来一个Flutter的图标。
Container(
width: 300,
height: 300,
decoration: FlutterLogoDecoration(
darkColor: Colors.red,
lightColor: Colors.green,
textColor: Colors.green
),
)
ShapeDecoration
的大部分用法和BoxDecoration
一直,需要注意的是他没有了设置圆角的功能,但是,border可是设置多个。每一个Border之间用 + 号链接。
decoration: ShapeDecoration(
color: Colors.red,
shape: Border.all(
color: Colors.black,
width: 10
) + Border.all(
color: Colors.blue,
width: 10
) + Border.all(
color: Colors.green,
width: 10
),
image: DecorationImage(
image: NetworkImage('https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=324769017,4079415235&fm=26&gp=0.jpg'),
colorFilter: ColorFilter.mode(Colors.red, BlendMode.screen),
fit: BoxFit.cover
)
)
这个属性也是基本上是不会使用的,只是给盒子添加一个下边框线
Text('UnderlineTabIndicator'),
Container(
width: 300,
height: 300,
decoration: UnderlineTabIndicator(
borderSide: BorderSide(
width: 10,
color: Colors.red
)
),
)
所以,关于decoration
这个属性,需要掌握的更多的还是BoxDecoration
这个类,功能比较多,但是常用的属性上面已经介绍到了,如果要想了解更多关于渐变以及图片滤镜方面的知识,可以查看Flutter之BoxDecoration用法详解。
foregroundDecoration
的使用与decoration
的使用时一样的,这里就不做过多的解释。
上面了解了Container的一些常用的属性,当时有的可能我们还处于一脸懵逼的状态,比如上面有了decoration
,为什么还有使用方法一模一样的foregroundDecoration
呢?其实这就和Container的绘制流程有关系。
Container的回执流程如下:
记住这个流程,然后再记住后面的回执的样式会覆盖前面绘制的样式。
关于Container的介绍接到这里,Container是Flutter中非常重要的一个Widget,一定要掌握。
关于同步代码可以查看https://github.com/tal007/FlutterApp。
获取更多关于Flutter的知识点,点击踏浪博客查看。