前言
学完了 Dart 语言,接下来就可以学习 Widget 了,Flutter 的 UI 界面就是由 Widget 组成的,Widget 的数量繁多,因此我会用几篇文章来专门介绍它,本篇就来介绍 Basics Widget。
1. 什么是 Widget
Flutter 的 Widget 的设计灵感来自于 React,主要目的就是使用 Widget 构建 UI。Widget 根据其当前配置和状态来描述视图,当 Widget 的状态发生更改时,Widget 会重建其描述。framework 将根据前面的描述进行对比,以确定底层渲染树从一个状态转换到下一个状态所需的最小更改。
在 Flutter 中,除了 Basics 的文本、图片、卡片、输入框这些基础控件,布局方式和动画等也都是由 Widget 组成的。通过使用不同类型的 Widget,就可以实现复杂的界面。
Widget 可以翻译为部件,粗略的相当于 Android 中的 View。Widget 和 View 不同的是:Widget 具有不同的生命周期:它是不可变的,每当 Widget 或者其状态发生变化时,Flutter 的框架都会创建一个新的 Widget 实例树。相比之下,Android 中的 View 会被绘制一次,并且在 invalidate 调用之前不会重绘。
2.Widget 的分类
Widget 的分类有很多类别,每个类别下面又包含很多 Widget,主要包括以下几种类别:
- Basics:在构建第一个 Flutter 应用程序之前,需要知道的 Basics Widget。
- Material Components:Material Design 风格的 Widget。
- Cupertino:iOS 风格的 Widget。
- Accessibility:辅助功能 Widget。
- Animation and Motion:动画和动作 Widget。
- Async:Flutter 应用程序的异步 Widget。
- Input:除了在 Material Components 和 Cupertino 中的输入 Widget 外,还可以接受用户输入的 Widget。
- Interaction Models:响应触摸事件并将用户路由到不同的视图中。
- Layout:用于布局的 Widget。
- Painting and effects:不改变布局、大小、位置的情况下为子 Widget 应用视觉效果。
- Scrolling:滚动相关的 Widget。
- Styling:主题、填充相关 Widget。
- Text:显示文本和文本样式。
Basics 有些特殊,它是由 Flutter 官方从其他的 Widget 分类中选取的一些 Widget 组成的,这些 Widget 是官方建议开发者构建第一个 Flutter 应用程序之前,需要知道的,目的是让开发者更快的入门。比如 Row 属于 Layout 分类,它就被选进了 Basics 中。本文遵循了 Flutter 官方的意图,首先介绍 Basics (Basics Widget)。
Widget 更多的是以组合的形式存在,比如 Container 是属于 Layout 中的一个 Widget,而 Container 又由 LimitedBox、 ConstrainedBox、Align、 Padding、 DecoratedBox、Transform 部件组成。 如果要实现 Container 的自定义效果,可以组合上面这些 Widget 以及其他简单的 Widget,而不是将 Container 进行子类化实现。
3.Widget 的状态分类
在 Android 中,我们可以通过直接更改 View 来更新视图。但是在 Flutter 中,Widget 是不可变的并且不会直接更新,而是必须使用 Widget 的状态。
Widget 有两种状态分类分别是无状态的 StatelessWidget 和有状态的 StatefulWidget,StatelessWidget 是不可变的,设置以后就不可再变化,所有的值都是最终的设置。StatefulWidget 可以保存自己的状态,但是 Widget 是不可变的,因此需要配合 State 来保存状态。
State 拥有自己的声明周期,如下所示:
名称 | 状态 |
---|---|
initState | create 之后被 insert 到渲染树时调用的,只会调用一次 |
didChangeDependencies | state 依赖的对象发生变化时调用 |
didUpdateWidget | Widget 状态改变时候调用,可能会调用多次 |
build | 构建 Widget 时调用 |
deactivate | 当移除渲染树的时调用 |
dispose | Widget 即将销毁时调用 |
4. 根 Widget 的种类
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
...
),
),
);
}
}
上面的 MaterialApp 就是一个根 Widget,也就是 Flutter 应用程序的第一个 Widget,根 Widget 有以下几种:
- WidgetsApp: 如果需要自定义风格,可以使用 WidgetsApp。
- MaterialApp:Material Design 风格的 Widget。
- CupertinoApp iOS 风格的根 Widget。
如果公司没有特殊要求,这里建议使用 MaterialApp 做为根 Widget 就可以了。
5.Basics Widget
Basics Widget 也就是 Basics,主要有以下几种:
- Container:一个便利的容器 Widget,可以设置 Widget 的背景、尺寸、定位。
- Row:在水平方向上布置子窗口 Widget 列表。
- Column:在垂直方向上布置子窗口 Widge 列表。
- Image:显示图像的 Widget
- Text:单一样式的文本。
- Icon:符合 Material Design 设计规范的图标
- RaisedButton:符合 Material Design 设计规范的凸起按钮。
- Scaffold:实现 Basics 的 Material Design 布局结构。
- Appbar:Material Design 的应用栏。
- FlutterLogo:以 Widget 形式来展示一个 Flutter 图标,可以调整样式。
- Placeholder:绘制一个框,为将来添加的 Widget 的占位。
这里选择一些我们必须要掌握的 Basics Widget 来进行讲解。
5.1 代码模板和主题
为了更好的理解这些 Basics Widget,我们需要写一些例子,这些例子需要一个代码模板,方便测试和学习。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(//1
title: 'Welcome to Flutter',
home: Scaffold(//2
appBar: AppBar(//3
title: Text('Basics Widget'),
),
body:
Padding(
padding: EdgeInsets.all(40.0),
child: Text('在这里编写和测试其他Basics Widget'),
),
),
);
}
}
上面的代码是稍微改动了官方的 Hello World 代码,便于测试,具体的代码含义已经在 Flutter 基础(二)Flutter 开发环境搭建和 Hello World 中讲过了,这里结合本文要讲的内容再说点细节。注释 1 处的 MaterialApp 属于 Material Components 类别中的 Widget,MaterialApp 中包含了实现 Material Design 的应用程序所需要的 Widget。
注释 2 和 3 处的 Scaffold 和 AppBar 同样也是 Material Components 类别中的 Widget,Scaffold 实现了 Material Design 布局结构,AppBar 是 Material Design 的应用栏,它们会在下一篇文章介绍 Material Components 时进行讲解。效果如下图所示:
5.2 文本
在 4.1 小节中已经用了 Text,还可以定义样式:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Welcome to Flutter',
home: Scaffold(
appBar: AppBar(
title: Text('Basics Widget'),
),
body: Padding(
padding: EdgeInsets.all(60.0),
child: Text(
'文本样式',
style: TextStyle(
fontSize: 16.0,
color: Colors.indigo,
fontStyle: FontStyle.normal,
fontWeight: FontWeight.bold,
),
),
),
),
);
}
}
这次为了便于理解列出了全部的代码,此后的举例只列出改变的部分。
通过 TextStyle 来定义文本的样式,效果如下:
5.3 图片
Image 的构造函数有多种:
- new Image:从 ImageProvider 获取图片
- new Image.asset:使用 key 从 AssetBundle 获取图片
- new Image.network:加载网络图片
- new Image.file:从文件中获取图片
- new Image.memory:用于从 Uint8List 获取图片
Image 的属性有很多种,主要的属性为 fit,用于表示图片的填充模式,参数类型为 BoxFit,BoxFit 的取值主要有以下几种,示例图片来自 flutter 官方。
contain
全图显示,保持原比例。
cover
全图充满,可能拉伸也可能被裁剪

fill
全图显示,通过拉伸来充满目标框 \

fitHeight
图片高度充满目标框,可能拉伸也可能被裁剪 \

fitWidth
图片宽度充满目标框,可能拉伸也可能被裁剪 \

none
保持图片的原始大小,剪裁掉位于目标框外的图片部分 \

scaleDown
与 contain 缩小图像的方式相同,只不过会在必要时缩小以确保图片完全在目标框内,如果不缩小等同于 none。

child: Image.network(
"https://upload-images.jianshu.io/upload_images/1417629-53f7d0902457cbe6.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240",
width: 260,
height: 100,
fit: BoxFit.fill,
),
效果如下图所示:
5.4 凸起按钮
凸起按钮 RaisedButton 是符合 Material Design 设计规范的按钮,可以通过 onPressed 来回调按钮的点击。
RaisedButton(
onPressed: () => print("onPressed"),
color: Colors.lightBlueAccent,
child: Text('RaisedButton', style: TextStyle(fontSize: 10)),
),
除了使用 RaisedButton,flutter 还提供了其他的按钮,比如 FlatButton、IconButton、FloatingActionButton 等等,它们的使用方法和 RaisedButton 大同小异,这里就不再赘述。
5.5 其他 Widget
Basics Widget 中的还有 Row、Column、Container 等 Widget,这里简单介绍下。
Row
Row 用于在水平方向显示数组中的子元素 Widget。
child: Row(
children: <Widget>[
Icon(Icons.access_alarm),
Icon(Icons.add_a_photo),
Icon(Icons.add_call),
],
),
垂直方向显示数组中的子元素 Widget 用 Column,使用方法和 Row 一样。这里需要提到的是 Expanded,可以用 Expanded 来配合 Row 和 Column 使用,用来填充剩余的空间。
Row(
children: <Widget>[
Icon(Icons.access_alarm),
Icon(Icons.add_a_photo),
Icon(Icons.add_call),
Expanded(
child: FittedBox(
fit: BoxFit.contain,
child: const FlutterLogo(),
),
flex: 2,
),
Expanded(
child: Text(
"占剩余部分的三分之一",
),
flex: 1,
),
],
),
其中的 Expanded 的作用是在自己的尺寸范围内缩放并且调整 child 位置,使得 child 适合其尺寸。FlutterLogo 是 Basics Widget 中的一种,用于展示 Flutter 图标。使用 flex 可以调整两个 Expanded 的占比。
Container
一个便利的容器 Widget,可以设置 Widget 的背景、尺寸、定位。描述起来有些抽象,可以理解它和 Android 中的 ViewGroup 差不多。
Container(
decoration:BoxDecoration(
color: Colors.lightGreen
),
child: Text('Container'),
padding: EdgeInsets.all(36.0),
margin: EdgeInsets.all(10.0),
),
Container 的 padding 和 margin 属性和 Android 中的作用是类似的:
总结
本文主要介绍了什么是 Widget、Widget 的分类、Basics Widget。因为 Widget 的数量繁多,官方将 Widget 进行了分类,并将需要先了解的 Widget 归入到了 Basics Widget 中,后续文章会介绍其他的 Widge 分类。
文章评论