通过上面 5 章的学习,我们已经完成了一个简单的猜数字小项目。这里将对项目在的一些知识点进行整理和总结,主要从界面相关知识和获得的技能点两个方面进行总结:
对于新手来说,Flutter 框架最最重要的就是完成界面在设备屏幕上的展示;并让用户在交互过程中展示准确的界面信息,以完成项目的功能需求。 从计数器和猜数字两个小项目中不难发现,组件 Widget
和界面呈现息息相关。
现实中的一处建筑,在地图上可以用经纬度信息进行表示;界面的呈现效果,也可以用组件的信息进行表示。通过一个东西,可以确定另一个东西,这是一种非常典型的 映射关系 。组件对象可以决定界面上的展示内容,组件在构建过程中的配置参数,就是用于控制界面呈现效果的。
所以,组件(Widget) 本质上是对界面呈现的一种配置信息描述。
世界会分为很多国家、国家会分为很多省、省会分成很多市、市会分成很多县、区…等等。这是一个非常典型的 树形嵌套结构 ,对于管理来说,这种结构是不可或缺却的,比如一个公司的组织架构、一本书的目录结构。
当个体数量非常庞大,需要进行维护管理时,树形嵌套结构 可以很有效地将整体划分为若干层级。从而各司其职,完成整体的有序运转,社会是如此,对于界面来说也是一样。对于可交互软件的开发者而言,设备的界面就是一个世界,包含着各种各样的视觉元素,用户在使用软件交互过程中的正确性,就是世界的有序运转。
只靠一个人管理整个社会,其他全部躺平是不现实的; 同样只靠一个组件来维护界面也不是明智之举。组件可以表示界面上的一部分,合理地划分 "屏幕世界"
的区域,交由不同的组件进行管理,是一个好的习惯。这得益于组件可以对界面构建逻辑的进行封装。
Widget 对象的所有属性都需要是 final
修饰的,也就是说你无法修改 Widget 对象的属性。前面说过 Widget 可以决定界面的呈现效果,也就是说对于一个 Widget 对象
而言,它对应的界面效果是无法变化的。但界面在交互过程中,一定会有界面变化的需求,比如说计数器项目,点击按钮时文字发生变化。
可能会有人疑惑,既然你说 Widget 对象无法修改属性,那计数器的数字为什么会变化。理解这个问题是非常重要的,所以先举个小例子:
现实生活中,一只狗自诞生那一刻,毛色属性就无法修改。 有一天,你去小明家,站在一只白狗面前。 小明对你说: “你把眼睛闭上。” 过一会你睁开眼,看到面前有一只黑狗。 那么,你是否会惊奇的认为,自己的闭眼操作会改变一只狗的毛色。 (其实只是小明换了一只体型一样的黑狗)
同理,计数器项目中,你点击按钮时,数字从 0 -> 1
。并不是 Text("0")
的文字属性变成了 1
,而是你面前的是一个新的 Text("1")
对象。数字需要在交互时发送变化,但不能再 Widget
类中变化,所以 Flutter 框架中,提供了一个状态数据维护的场所: State
的衍生类。它可以提供 setState
触发重新构建,从而更新界面呈现。
对于新手而言,自己创建 Widget 的派生类,有两个选择。其一是继承自 StatelessWidget
, 其二是继承自 StatefulWidget
, 两者都可以通过已有的组件完成拼装的构建逻辑。
StatelessWidget
派生类是很简单直接的,它在 build
方法中通过已有组件来完成构建逻辑,返回 Widget 对象。 界面上需要什么,就在构造函数中传什么。相当于一个胶水,把其他组件黏在一块,作为新的组件个体。
StatefulWidget
和 StatelessWidget
在功能上是类似的,只不过 StatefulWidget
自己不承担 build
组件的责任,将构建任务委托给 State
派生类。它会通过 createState
方法创建 State
对象:
在上一点中提到,State
派生类中可以维护状态数据的变化和重新触发自己的 build 构建方法,实现界面的更新。另外,State
对象有生命周期回调,可以通过覆写方法进行感知。
需要注意一点: 不要将 StatefulWidget 和 State 混为一谈,两者是不同的两个类型。可以感知生命周期、维护状态数据变化的是 State 类。 StatefulWidget 的任务是承载配置信息,和创建 State 对象。
虽然说界面上展示的内容都是通过 Widget 确定的,但 Flutter 中除了 Widget 还有很多其他的类型对象。它们在一起共同工作,维护界面世界的运转。
函数本身可以视为一个对象,作为函数的参数进行传递,这样可以在一个类中,很方便地感知另一个对象事件的触发。比如在 _GuessPageState
类中,使用 FloatingActionButton 组件,它的入参 onPressed
是一个函数,这个函数是由框架内部在恰当的时机触发的,这个时机就是点击。
也就是说,点击会触发 onPressed
参数传入的函数对象,这样我们就可以方便地 监听到 事件,并处理数据变化的逻辑。这种函数,就称之为 回调函数 。既然函数要作为对象传递,那最好要有类型名,可以通过 typedef
让函数有用类名:
比如, FloatingActionButton 的 onPressed 参数类型是 VoidCallback
,定义如下:表示一个无参的返回值为空的函数。
typedef VoidCallback = void Function();
AnimatedBuilder 组件的 builder 参数也是一个回调函数,类型为 TransitionBuilder
,定义如下:表示一个返回值为 Widget, 两个入参分别是 BuildContext 和 Widget? 的函数。
typedef TransitionBuilder = Widget Function(BuildContext context, Widget? child);
动画控制器是界面可以进行动画变化的驱动力,使用过程分为三步: 创建动画控制器、 在合适时机启动控制器、使用动画器的值构建界面
1.创建动画控制器主要在 State
派生类中进行:让 State
派生类混入 SingleTickerProviderStateMixin
后,将状态自身作为 AnimationController 的 vsync 入参:
class _GuessPageState extends State<GuessPage> with SingleTickerProviderStateMixin{
late AnimationController controller;
@override
void initState() {
super.initState();
controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 200),
);
}
2.在恰当的时机可以通过 AnimationController 的 forward 方法启动控制器。让它的值从 0 变化到 1 :
controller.forward(from: 0);
3.根据动画控制器的值,设置需要动画变化的属性。由于动画的触发非常频繁,推荐使用 AnimatedBuilder
监听控制器,实现局部组件的更新和构建:
Dart 内部提供了 Random
类,因此获取随机数就非常方便。只要创建 Random 对象,提供 nextInt
就可以得到 0 ~ 100
的随机整数 (不包括 100) :
Random _random = Random();
_random.nextInt(100);
另外,可以通过 nextDouble
方法获取 0 ~ 1
的随机小浮点数 (不包括 1) ;通过 nextBool
方法获取随机的 bool 值:
最后来整理一下目前猜数字项目中用到的 Flutter 内置组件,大家可以根据下表,结合源码以及应用界面,思考一下这些组件的作用和使用方式:
基础组件是常用的简单组件,功能单一,相当于积木的最小单元:
组件名称 | 功能 | 猜数字中的使用 |
---|---|---|
Text | 文本展示 | 展示相关的文字信息 |
TextField | 输入框展示 | 头部的输入框,得到用户输入 |
Container | 一个容器 | 对比较结果界面进行着色 |
Icon | 图标展示 | 作为图标按钮的内容 |
IconButton | 图标按钮,通过 onPressed 监听点击回调 | 头部运行按钮, |
FloatingActionButton | 浮动按钮 ,通过 onPressed 监听点击回调 | 右下角按钮,生成随机数 |
有些组件是比较复杂的,在构造中可以配置若干个组件,作为各个部分。比如 AppBar
可以设置左中右下四个区域,Scaffold
可是设置上中下左右,它们像躯干一样,把布局结构已经固定了,只需将组件插入卡槽中即可。
组件名称 | 功能 | 猜数字中的使用 |
---|---|---|
MaterialApp | 整体应用配置 | 作为代码中的组件顶层,提供主题配置 |
Scaffold | 通用界面结构 | 这里通过 appBar 设置标题、 body 设置字体内容 |
AppBar | 应用标题栏 | 展示标题栏 |
布局组件无法在界面上进行任何色彩的展示,它们的作用是对其他组件进行排布与定位。比如 Row
和 Column
用于水平和竖直排列组件;Stack
让若干组件叠放排布;Center
可以将子组件居中。
组件名称 | 功能 | 猜数字中的使用 |
---|---|---|
Row、Column | 水平、竖直摆放若干组件 | 通过 Column 竖直排列文字信息和比较结果 |
Expanded、Spacer | 延展区域 | 比较结果通过 Spacer 占位 |
Stack | 叠放若干组件 | 比较结果和主体内容进行叠放 |
Center | 居中定位 | 主体内容居中 |
构建器是指,通过该组件回调来完成构建组件的任务。也就是说回调触发时会进行重新构建,从而让构建缩小在局部。
组件名称 | 功能 | 猜数字中的使用 |
---|---|---|
AnimatedBuilder | 监听动画器,通过回调局部构建组件 | 比较结果中文字的大小动画 |
到这里,猜数字的项目就总结完了,希望大家可以好好思考和体会,下面将进入 电子木鱼 的模块。
© 2019 - 2023 Liangliang Lee. Powered by gin and hexo-theme-book.