Flutter 组件基础
当组件的状态发生改变时,组件会重构自身的描述,并且Flutter框架会对比之前的描述,以确定地层渲染树从当前状态转换到下一个状态所需要的最小更改,最后再执行界面的刷新。
Flutter中真正代表屏幕现实元素的类是Element。Widget只是描述Element的配置数据而已,并且一个Widget可以对应多个Element。如下图所示;
StatelessWidget
表示没有状态的组件。如果想要创建一个无状态的组件,只需要继承 StatelessWidget 根组件,并且重写 build() 方法即可。
由于没有状态,因此StatelessWidget只在初识话阶段构建Widget时才会执行一次渲染,因此它无法基于任何时间或用户操作重绘试图。
class MyApp extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
throw UnimplementedError();
}
}
在该继承和重写的方法中,出现了一个build方法,有一个参数为context。context是当前Widget在Widget树中执行相关操作的一个句柄。可以使用它向上遍历Widget树以及按照Widget类型查找父级Widget。
StatefulWidget
表示有状态的Widget。通过与State对象进行关联来管理组件状态树,内部成员变量不需要使用final修饰符,当需要更新内部变量时,直接使用 setState() 即可。如果Flutter监听到状态树发生变化,那么会触发视图重绘。
如果需要创建一个有状态的组件,需要继承 StatefulWidget ,并且重写 build() 。
class MyApp extends StatefulWidget{
@override
State<StatefulWidget> createState() {
// TODO: implement createState
throw UnimplementedError();
}
}
class MyAppState extends State<MyApp>{
void method(){
setState(() {
//进行状态的变更
});
}
@override
Widget build(BuildContext context) {
// TODO: implement build
throw UnimplementedError();
}
}
对比于StatelessWidget而言,StatefulWidget多了一个状态。当内部东西需要变更时,通常是调用setState()方法,从而让内部的状态发生改变,从而让Flutter进行重绘。在StatefulWidget中新引入了一个 State<*> 这个是状态改变类。
MaterialApp
作为提供入口的Widget
序号 | 名称 | 作用 |
---|---|---|
1 | title | String类型,Android设备中APP上方显示的标题,在IOS中不起作用。 |
2 | home | Widget类型,默认启动后的第一个Flutter。 |
3 | routes | Map< String, WidgetBuilder >类型,顶级路由表。 |
4 | theme | 定义应用主题 |
5 | theme.primarySwatch | 应用的主题色 |
6 | theme.primaryColor | 单独设置导航栏的背景颜色 |
AppBar
顶部导航栏组件,可以用来控制路由、标题和溢出下拉菜单。
序号 | 名称 | 解释 |
---|---|---|
1 | leading | 标题左边的图案按钮,默认是返回箭头的形式 |
2 | title | 导航栏标题 |
3 | actions | 右边的动作区域中可以放置多个组件,可以是图标或者文字 |
4 | flexibleSpace | 位于标题下面的空白空间 |
5 | bottom | 位于导航栏地步的自定义组件 |
6 | elevation | 控制下方阴影栏的坐标 |
7 | backgroundColor | 导航栏的颜色 |
8 | brightness | 导航栏材质的亮度 |
9 | textTheme | 文本主题设置 |
10 | primary | 导航栏是否显示在任务栏顶部 |
11 | centerTitle | 标题是否居中现实 |
12 | titleSpacing | 标题的间距 |
13 | toolbarOpacity | 导航栏透明度,从1到0,透明度从完全不透明到完全透明 |
AppBar如下图所示
Scaffold
具有Material Design布局风格的Widget,被设计为MaterialApp的顶级容器组件,可以自动填充可用的屏幕空间,占据整个窗口或者设备屏幕。
编号 | 名称 | 说明 |
---|---|---|
1 | appBar | 用于设置顶部的状态栏,如果不设置,那么不显示 |
2 | body | Widget类型,现实Scaffold内容的主要容器 |
3 | bottomNavigationBar | 设置Scaffold的底部导航栏,items的数量 > 2 |
4 | drawer | 设置抽屉效果 |
5 | floatingActionButton | 设置右下角的安宁 |
对于Scaffold中,有一个示例代码如下:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('首页'),
),
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
currentIndex: 1,
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.account_balance),
title: Text('银行')
),
BottomNavigationBarItem(
icon: Icon(Icons.contacts),
title: Text('联系人')
),
BottomNavigationBarItem(
icon: Icon(Icons.library_music),
title: Text('音乐')
)
],
),
body: const Center(
child: Text('联系人页面'),
),
),
);
}
}
经过编译,现实的结果如下:
文本组件
文本组件是Text组件,组件的基本属性如下表
编号 | 属性名称 | 类型 | 说明 |
---|---|---|---|
1 | data | String | 显示文本的内容 |
2 | style | TextStyle | 文本的样式 |
3 | strutStyle | StrutStyle | 每行的最小行高 |
4 | textAlign | TextAlign | 文本的对齐方式 |
5 | textDirection | textDirection | 文字方向 |
6 | locale | Locale | 选择用户语言和格式设置的标识符 |
7 | softWrap | bool | 是否支持换行 |
8 | overflow | TextOverflow | 文本的截断方式 |
9 | textScaleFactor | double | 文本相对于默认字体大小的缩放因子 |
10 | maxLines | int | 文本显示的最大行数 |
11 | semanticsLabel | String | 给文本添加一个语义标签 |
按钮组件
Material组件库中有多个按钮组件
- RaisedButton
- FlatButton
- OutlineButton
- IconButton
按钮的样例代码如下
import 'package:flutter/material.dart';
void main() => runApp(ButtonWidget());
class ButtonWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Button 组件'),),
body: Center(
child: Column(
children: <Widget>[
FlatButton(onPressed: () => print('FlatButton'), child: Text('Flat'),),
RaisedButton(onPressed: ()=>print('RaisedButton'),child: Text("RaisedButton"),),
FloatingActionButton(onPressed: ()=>print('FloatingActionButton'),child: const Text('FloatingActionButton'),),
OutlineButton(onPressed: ()=>print('OutlineButton') ,child: const Text("OutlineButton"),),
IconButton(onPressed: ()=>print("IconButton"), icon: const Icon(Icons.thumb_up))
],
),
),
),
);
}
}
在代码中,除了FloatingActionButton和IconButton没有被废弃以外,其他均被废弃,不推荐使用。
编号 | 属性名称 | 类型 | 说明 |
---|---|---|---|
1 | textColor | Color | 按钮的文字颜色 |
2 | disabledTextColor | Color | 按钮禁用时的文字颜色 |
3 | color | Color | 按钮的背景颜色 |
4 | highlightColor | Color | 按钮按下时的背景颜色 |
5 | splashColor | Color | 单击时产生的水波动画中的水波颜色 |
6 | colorBrightness | Brightness | 按钮的主题 |
7 | padding | EdgeInsetsGeometry | 按钮填充距离 |
8 | shape | ShapeBorder | 按钮的外形 |
9 | child | Widget | 按钮的文字内容 |
10 | onPressed | VoidCallback | 按钮点击回调 |
图片组件
图片组件是用来加载和显示图片的组件。可以使用不同的方式进行加载不同形式的图片。
- Image 通过ImageProvider来加载图片
- Image.asset 用来加载本地的图片
- Image.file 用来加载本地 .file 文件类型的图片
- Image.network 用来加载网络图片
- Image.memory 用来加载内存缓存图片
编号 | 属性名 | 类型 | 说明 |
---|---|---|---|
1 | scale | double | 图片显示的比例 |
2 | semanticsLabel | String | 给Image加上一个语义标签 |
3 | width | double | 图片的宽,如果为null,会以默认的形式显示 |
4 | height | double | 图片的高,如果为null,会以默认的形式显示 |
5 | color | Color | 图片的混合颜色 |
6 | fit | BoxFit | 图片的填充模式 |
alignment | Alignment | 图片的对齐方式 | |
repeat | ImageRepeat | 当图片本身小雨显示空间时,指定图片的重复规则 | |
centerSlice | Rect | 在矩形范围内的图片会被当成.9格式的图片 | |
matchTextDirection | Bool | 图片的绘制方向,true表示从左往右,false表示从右往左 | |
gaplessPlayback | Bool | 当图像提供者发生更改时,是否保留原图像 | |
filterQuality | FilterQuality | 图片的过滤质量 |
fit填充模式
- BoxFit.fill 全图显示,不够的部分拉伸
- BoxFit.contain 全图显示,超过部分被裁减
- BoxFit.cover 默认显示规则
- BoxFit.fitWidth 宽度上充满空间,高度按比例缩放,超出部分被裁剪
- BoxFit.fitHeight 高度充满空间,宽度按比例,超出部分裁剪
- BoxFit.scaleDown 与contain效果差不多,但是会缩小图像以确保图像位于显示空间内
- BoxFit.none 没有填充策略,按原大小显示
Image组件图片是有缓存的,默认最大缓存数量是1000,最大空间为100MB。
图标组件
Icon组件是图标组件,也可以使用IconButton。常用组件如下
- IconButton 可交互的Icon组件
- Icons 自带的Icon组件集合
- IconTheme Icon组件主题
- ImageIcon 通过AssetImages或者图片显示Icon组件
Icon的基本的属性如下
序号 | 属性名称 | 类型 | 说明 |
---|---|---|---|
1 | size | double | 图标的大小 |
2 | color | Color | 图标的颜色 |
3 | semanticsLabel | String | 给图标添加一个语义标签 |
4 | textDirection | TextDirection | 图标的绘制方向 |
输入框组件
输入框组件TextField是一个文本输入框组件。常见的属性如下:
序号 | 属性名称 | 说明 |
---|---|---|
1 | controller | 输入框控制器,可以获取和设置输入框的内容以及舰艇文本内容的改变,可自动创建 |
2 | focusNode | 控制TextField组件是否获取输入焦点,用户和键盘交互的一种常见方式 |
3 | decoration | 用于控制TextField组件的外观显示 |
4 | textAlign | 输入框内文本在水平方向的对齐方式 |
5 | textDirection | 输入框内文本的方向 |
6 | keyboardType | 用于设置默认的键盘输入类型 |
textInputAction | 回车键为动作按钮图标 | |
8 | style | 输入框的样式 |
9 | autofocus | 是否自动获取焦点,默认false |
10 | obscureText | 是否隐藏正在编辑的文本内容 |
11 | maxLines | 输入框文本的最大行数 |
12 | maxLength | 输入框中允许的最大字符数,使用此属性会在右下角显示已输入的字符数 |
13 | onChange | 输入框内容改变时的回调函数 |
14 | onEditingComplete | 输入框输入完成时触发 |
15 | onSubmitted | 输入框输入完成时触发,返回输入内容 |
16 | inputFormatters | 指定输入格式 |
17 | enabled | 是否禁用输入框 |
18 | enableInteractiveSelection | 是否启用交互式选择,为true时表示长选文字,并且弹出cut、copy、paste菜单 |
19 | keyboardAppearance | 设置键盘的亮度模式,IOS专用 |
20 | onTap | TextField组件的点击事件 |
21 | buildCounter | 自定义InputDecorator.counter小部件的回调方式 |
表单组件
Form是一个包含表单元素的表单组件,可以用来对输入的信息进行校验。表单的一些属性如下
编号 | 属性名称 | 类型 | 说明 |
---|---|---|---|
1 | child | Widget | 表单的子组件 |
2 | autovalidate | bool | 是否自动验证表单内容,默认false |
3 | onWillPop | WillPopCallback | 表单所在的路由是否可以直接返回 |
4 | onChanged | VoidCallback | 表单子元素发生变化时触发的回调 |
import 'package:flutter/material.dart';
void main(List<String> args) {
runApp(FormWidget());
}
class FormWidget extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return FormWidgetState();
}
}
class FormWidgetState extends State<FormWidget> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
String? _userName;
String? _userPassword;
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "flutter demo",
theme: ThemeData(
primaryColor: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text("Form组件"),
),
body: Form(
key: _formKey,
child: Column(
children: [
TextFormField(
decoration: const InputDecoration(
hintText: "用户名",
icon: Icon(Icons.person)
),
validator: (value) {
if (value?.length != null && value!.length <= 5) {
return "用户名需要大于5个字符";
}
},
),
TextFormField(
decoration: const InputDecoration(
hintText: "密码",
icon: Icon(Icons.lock)
),
obscureText: true,
validator: (value) {
if (value?.length != null && value!.length <= 8) {
return "密码必须大于8字符";
}
},
),
RaisedButton(
onPressed: () {
if(_formKey.currentState?.validate()==true){
_formKey.currentState?.save();
}
},
padding: EdgeInsets.all(15.0),
child: Text("login"),
color: Theme
.of(context)
.primaryColor,
textColor: Colors.white,
),
],
),
),
),
);
}
}
根据上面的代码进行编译运行后,能得到两个简单的输入框以及一个按钮,当用户名或者密码不符合预期时,便会提示错误的信息。
容器组件
Container是Flutter提供的容器组件,可以包含一个子组件,自身具备alignment、margin、padding等基础属性。其包括的属性如下:
序号 | 属性名称 | 类型 | 说明 |
---|---|---|---|
1 | key | Key | Widget的标识,用于查找更新 |
2 | alignment | AlignmentGeometry | 容器内子组件的对齐方式 |
3 | padding | EdgeInsetsGeometry | 容器的内边距 |
4 | color | Color | 容器的背景颜色 |
5 | decoration | Decoration | 容器的背景装饰 |
6 | foregroundDecoration | Decoration | 容器的前景装饰 |
7 | width | double | 容器的宽度 |
8 | height | double | 容器的高度 |
9 | constraints | BoxConstraints | 容器的约束条件 |
10 | margin | EdgeInsetsGeometry | 容器的外边距 |
11 | transform | Matrix4 | 容器的变化矩阵 |
12 | child | Widget | 容器里面的子组件 |
padding包含容器内部的边距,margin是外部的边距。点击padding中的区域会有事件响应,而margin的区域则不会。
盒约束模型
指组件可以按照指定限制条件来决定如何布局自身位置。常见的组件包括
- ConstrainedBox
- SizedBox
- UnconstrainedBox
ConstrainedBox
常见的盒约束组件,用来对子组件添加额外的约束。
ConstrainedBox{
Key key,
@required this.constraints,
Widget child
}
SizedBox
用于给子元素指定固定的宽和高
SizedBox{
double width,
double height,
Widget child
}
SizedBox是ConstrainedBox的子类。
UnconstrainedBox
不会对子组件产生任何限制,允许子组件按照自己本身的大小进行绘制,比较少用到。
参考书籍 《Flutter跨平台开发入门与实战》