文章目录

  • 一、分析一个新的flutter项目
  • 二、程序设计语言的工作原理
  • 三、从头开始理解函数
  • 四、如何启动flutter应用程序
  • 五、理解小部件
  • 六、使用第一个小部件并将值传递给函数
  • 七、位置参数和命名参数
  • 八、组合多个小部件
  • 九、理解const值
  • 十、构建更复杂的部件树
  • 十一、了解值类型
  • 十二、配置小部件和了解对象
  • 十三、使用配置对象(非部件对象)
  • 十四、泛型,列表和添加渐变颜色
  • 十五、如何配置小部件和对象
  • 十六、练习文本样式
  • 十七、自定义小部件,为什么需要它们
  • 十八、理解类
  • 十九、构建自定义小部件
  • 二十、使用构造函数
  • 二十一、跨文件拆分代码
  • 二十二、练习创建自定义小部件
  • 二十三、引入变量
  • 二十四、变量和类型-结合两个关键概念
  • 二十五、final & const -特殊类型的变量
  • 二十六、实例变量(属性)和可配置的小部件
  • 二十七、练习可重用的部件和构造函数
  • 二十八、显示图像和使用多个构造函数
  • 二十九、添加按钮和使用函数作为值
  • 三十、按钮样式和填充
  • 三十一、有状态小部件介绍
  • 三十二、生成随机数,完成摇骰子效果
  • 三十三、总结

一、分析一个新的flutter项目

在硬盘上的任何位置创建一个新的flutter项目

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter

dart文件在lib文件夹中,lib是存放dart和flutter代码的文件夹:

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_02

各个平台的文件夹仅包含平台特定的文件,通常情况下不用更改,flutter在需要时自动更改和配置这些文件。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_03

build文件夹只包含flutter为不同目标平台构建应用时生成的临时文件和输出文件

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_04

test文件夹可以编写测试主应用程序代码的代码,可以定义自动化测试,对于早期捕获错误以及确保不必手动测试所有内容非常有用。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_05

以.开始的文件夹,保存了一些额外的配置

.gitignore是git使用的文件,版本控制软件,可以用来管理代码快照。

.metadate由flutter自动管理,用于跟踪有关项目的一些内部信息和元数据。

analysis_options.yaml配置了一些flutter和dart工具,代码编辑器使用这些工具在运行应用程序之前显示代码中的警告和错误。默认设置足够了,也可以根据喜好调整这些设置,例如:强制执行某种编写代码的风格,如果不小心使用了另外一种风格或类似的东西会警告。

pubspec.yaml可以编辑,可以添加第三方软件包到flutter项目。你想为你的应用程序添加一些功能,而不想自己构建,因为太麻烦或者复杂,但它也没有内置在flutter或dart中,就可以引入一个第三方软件包。

README.md文件中包含了一些关于这个项目的一般信息,简短的描述和一些资源,可以访问这些资源深入了解flutter

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_06

二、程序设计语言的工作原理

像dart这样的代码不会被andriod或iOS设备理解,在编译之前,dart最终会从上到下遍历这个代码文件,并从上到下读取代码文件,解析这个代码文件。

void main() {
  runApp(const MyApp());
}

代码和代码文件由dart解析,构建项目以便在目标平台上运行。

代码被解析之后,他必须被翻译成目标平台可以理解的语言,刚刚提到的,这些代码不能在andriod或iOS或其他目标平台上执行。

下一步,在解析代码之后,代码被各种dart和flutter工具编译,意味着他被转换成一些其他代码,一些原生ios或andriod机器代码,因此,这些代码可以被ios或andriod或任何目标平台所理解。

因此,使用dart和flutter编写的代码将被转换成其他代码,然后这些代码最终被打包,捆绑在一起成为一个高度优化的代码包,然后,该代码包再将项目交付到的设备上执行。

以上就是dart代码的情况。这些目标设备上执行的是编译后的代码。

三、从头开始理解函数

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_07

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

可以看到一堆单词,一堆单词行,不是真正的句子,只是单词的组合,这就是编程的全部。

组合不同的单词来创建语句、指令,然后告诉计算机或移动终端最终要做什么,在屏幕上显示什么,点击按钮时要做什么等等。

创建这些指令有两个主要类别的单词

第一类是关键字(keywords),这些词内置在一种语言中,在该语言中执行或触发非常特定的事情。

例如,import是内置在Dart中的关键字,最终将一个文件连接到另一个文件。

另一类词是标识符,作为一个开发人员自己定义的词。例如以下代码中的MyApp,也可以用其他替换,例如MeineApp

class MyApp extends StatelessWidget {
  const MyApp({super.key});

像visual studio code这样的代码编辑器可以检测不同类型的单词,有一个语法突出的显示的内置功能,使代码更具有可读性,为不同的单词分配不同的颜色。例如extends/class和import都是蓝色都是关键字。不同的颜色被用于不同种类的单词。

runApp();

这就是函数,函数是可以在代码中执行的简单指令,runApp是一个函数,一个由flutter框架提供的指令,这个指令是关于启动和运行应用程序的,它的主要工作实际上是在屏幕上显示一些用户界面。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_08

有条红色的曲线,表示代码有问题。鼠标悬停在错误上,会看到问题的详细描述。

必须提供函数体

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_09

创建一个自定义函数,一个自定义指令。

void 后面跟自定义函数的自定义命令的名称

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_10

这就是定义自定义函数的方式,这里的main就是函数名,void是返回类型,开始和结束花括号之间的这部分是函数体,是这个函数执行时应该执行的代码。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#开发语言_11

按需调用这个函数代码,将执行这个函数。定义了函数,在代码其他地方,可以调用他们,

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_12

将函数runapp放到main函数的函数体中

新的错误,找不到这个函数,你必须告诉你的程序runapp来自flutter

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_13


Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_14

这里flutter已经作为依赖添加了。

使用import添加导入路径,使其能找到runapp函数,

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_15

理解函数、调用函数和函数定义以及flutter应用如何启动非常重要。

四、如何启动flutter应用程序

main()函数到底是如何执行的呢?

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_16

函数可以被定义,但他们必须被调用,被执行才能真正运行他们定义中的代码。

如果只是定义了一个函数,而从来没有在函数内部调用过它,那么实际上不会被执行。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_17

main函数是dart中的一个特殊函数。这也是为什么上面这些奇怪的指令会自动添加到代码编辑器中,因为main函数是dart应用程序的主要入口点。

准确的说,是main.dart文件中的主函数,当应用程序在设备上激活时,

它将由dart自动执行,因此,在代码被解析和编译之后,当它在设备上执行时,main函数的编译版本会通过dart在该设备上自动执行,

因此不需要手动调用main,在main函数中,调用runapp函数,因为只是激活flutter app或启动flutter app并在屏幕上绘制一些用户界面的另一个重要步骤,因为runapp会告诉flutter在屏幕上显示什么。

五、理解小部件

现在有一个错误,需要一个位置参数

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_18

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_19

可以在源代码中看到runapp被定义为期望一些输入值,这就是括号之间的部分,可以指定函数正确工作所需的输入值列表。

有些函数不需要任何输入,比如main,其他函数会这样做,这些输入值称为参数或实参。定义函数时或调用函数时称为参数。

runApp知道什么显示在屏幕上?它需要的输入值就是应该在屏幕上显示的内容。

对于运行的应用程序,需要一个小部件或小部件树作为值,因为flutter的用户界面是用小部件构建的。当构建一个flutter应用时,不会使用一些可视化的拖放编辑器,而是使用小部件在代码中构建用户界面,通常将许多小部件相互组合,将这些小部件相互嵌套来构建界面。由于将小部件嵌套在一起,实际上最终会得到一个小部件树,在这个树的顶部有一些根小部件,然后可能是一个子小部件和另一个子小部件,然后可能会包含多个子小部件。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_20

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_21

flutter用户界面是通过组合和嵌套小部件来创建的,例如,通过添加文本小部件,这是flutter提供的在按钮小部件内部的屏幕上显示文本的功能,使按钮具有一些文本。flutter提供了许多内置的小部件可以在代码中使用,如按钮,表单输入,布局小部件,也可以构建自定义小部件。

六、使用第一个小部件并将值传递给函数

官方widgits:https://docs.flutter.dev/ui/widgets

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_22

现在我们调用MateriaApp,在某种程度上它就像一个函数,但它实际上是一个所谓的类或类的构造函数。MateriaApp几乎在所有要构建的flutter应用中使用,因为这是用作起点的主要小部件。最后传递给runApp,MateriaApp这个主部件为用户界面做了很多幕后的设置工作,确保了界面可以正确地显示在屏幕上,但现在屏幕上什么都没有显示,需要向MateriaApp传递另一个参数,以在屏幕上显示某些内容。

当调用MateriaApp时,我们正在创建这样一个应用小部件,告诉flutter在屏幕上显示这个MateriaApp()小部件,这是UI的一部分,不管它是什么,都是传递给runApp的值。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_23

将输入值传递给函数,以便函数可以对这些输入值执行某些操作,是编程的关键部分。

七、位置参数和命名参数

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#开发语言_24

MaterialApp还需要一个输入值,用来定义应用程序UI中应该显示的内容,MaterialApp没有太多的信息来运行应用程序,屏幕上该显示什么

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_25

函数可以接受多个逗号分隔的参数,然后传入值并按位置匹配。调用函数时提供给该函数的第一个值将映射到第一个参数,第二个值将映射到第二个参数

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_26

在定义函数的代码中,命名参数用花括号{}括起来,与位置参数或实参相比,区别在于调用函数时传递值的顺序并不重要,而是通过名称来标识这些参数。这正是MaterialApp在内部实现的方式,有一个很长的命名参数列表用花括号括起来了所有的这些参数,这些参数就被简单的命名了。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_27

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_28

home命名参数很重要,这是必须为MaterialApp设置的主要参数,用于定义哪种widget哪种UI元素应该显示在传递给运行app的应用UI中。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_29

通过内置的文本小部件来显示一些文本,也跟MaterialApp一样,文本小部件来自于flutter由flutter团队提供。

八、组合多个小部件

把鼠标悬停在文本小部件上,它实际上也接受一些命名参数。{}之间的一长串参数,也有一个位置参数,在这里,data这个位置参数确实是我们在使用文本时必须设置的。定义函数时,可以根据需求混合匹配这些不同的参数类型。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_30

传递一段数据是可读的文本,文本用单引号或者双引号括起来。单引号更常见。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_31

我们有了第一个基本的小部件组合,创建了文本小部件,并将其传递给MaterialApp,然后传递给runApp。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#开发语言_32

如果有模拟器在运行,可以通过两种方式来运行看看效果。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_33

九、理解const值

得到了第一个屏幕输出,第一个基本UI。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_34

蓝色的曲线证明没有错误,但是有一些改进的空间,代码不是最佳的。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#开发语言_35

建议应该在构造函数中使用const来提高性能。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#开发语言_36

const是一个关键字,可以通过颜色来判断,它与void和import颜色相同,是内置在dart语言中的关键字,const是一个关键字和一个功能,用于帮助dart优化应用程序运行时的性能。

如果你讲某个东西标记为const,比如在应用程序中使用的一个文本小部件,那么这个文本小部件将存储在运行应用程序的设备的内存中,无论你是否使用const,一旦你的代码执行了你的代码所创建的东西,比如小部件,就会被存储在设备内存中。但是使用const,当你在应用程序中第二次使用相同的小部件或相同的文本时,现有的内存对象将被重用,而不是创建第二个内存对象。使用const允许dart重用相等的值,并避免内存中的数据重复,从而让应用程序更具有内存效率并提高整体性能。

cosnt Text('Hello World!')

现在并不用记住需要在哪个小部件前加const,代码编辑器会告诉你哪些地方要添加和删除。例如我在文件小部件前也添加,会告诉我删除,因为MaterialApp前已经添加了。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_37

十、构建更复杂的部件树

怎么让界面变得漂亮呢?为了让它变得更漂亮,必须添加更多的小部件。另一个内建的小部件scaffold小部件可以帮助我们更好的实现这个功能,帮助我们在app中设置一个好看的屏幕。MaterialApp是根小部件,它对于设置整个app非常重要,但许多app由多个屏幕组成,这些屏幕也必须设置,即使在app中只有一个屏幕,就像我们这里看到的这样,这个屏幕必须设置为有一个漂亮的背景颜色,以便在它的子部件上强制一些基本的样式等等。

在这里,我们用scafflod小部件包装文本,scafflod必须在MaterialApp内部,但应该包装在属于屏幕小部件周围。

如果想知道哪个小部件需要哪种参数,可以将鼠标悬停在小部件上了解可接受的参数,body的值是应该在这个scafflod小部件中显示的小部件。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_38


Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_39

运行一下:

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#开发语言_40

hello world可以在另一个小部件的帮助下实现在屏幕上居中,

用一个部件小部件center来包装文本,

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#开发语言_41

除了手动添加外,还可以右击文本小部件,点击重构,会得到一些重构建议,编程中的重构就是改变你现有代码的过程。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_42

点击使用center小部件来包装文本小部件

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_43

将自动创建center小部件,并将文本小部件传递给center小部件的命名子参数。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#开发语言_44

现在这行代码越来越长,但这仍然是一个简单的小部件树,为了让代码易于阅读和维护,使其更有结构性,dart提供了一个很好的技巧来帮助格式化小部件树,在每个右括号后面添加逗号,除了最后一个需要分号的地方。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_45

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#开发语言_46

运行格式化文档命令,点击或使用快捷键,现在更易于理解这个小部件树,有了一些漂亮的缩进,可以显示哪个小部件在哪个小部件的内部。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_47

保存一下代码看一下效果,如果没有更改,刷新重启一下

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_48

可以看到文本在屏幕中央了,通过添加这两个内置小部件,scafflod和center,再次改进了app。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_49

十一、了解值类型

类型是DART的一个重要的基本概念,dart是一种类型安全语言,意味着使用的所有值都是某些类型。例如字符串,int。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_50

每个值不仅仅有一个类型,通常有多重类型。例如,多有的值至少都是对象类型,然后它们也有更具体的类型。这些类型内置在dart中,或由第三方包提供,或由在创建自己的类型时提供。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#开发语言_51

鼠标放在hello world上,可以看到代码编辑器显示的信息,该值的类型。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#开发语言_52

app函数参数信息前面

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_53

为什么会有这种类型的特征呢

它存在,并且由dart强制执行,确保永远不会意外的在错误的地方使用错误的类型,例如text文本小部件只处理字符串,不然会报错:

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_54

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_55

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_56

data是参数名,前面的注释是该参数所期望的类型。

例如自定义一个函数,参数为int数字类型,如果你向这个函数传递一些文本,你会得到错误:

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_57

例如runapp函数需要一个小部件作为它的第一个也是唯一的参数,

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_58

widget类型的值,结果证明,materialapp也就是传递给runapp的值,就是这样一个小部件

这就是类型背后的思想,在dart中,类型无处不在,而不仅仅是在函数的参数列表中。例如main前面的void也是一个类型,它是main函数的返回值类型。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_59

可以自己构建类型,也可以通过第三方软件包获得许多类型,还有一些dart内置的核心类型:

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_60

十二、配置小部件和了解对象

把背景颜色从白色变成一个漂亮的渐变色,同时改变文字

scaffold小部件,除了设置body参数在scafflod内部显示的小部件外,还可以设置其他scaffold支持的参数,例如颜色

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_61

大多数小部件都允许将值传递给不同的参数,有一些需要小部件的参数,也有一些参数不需要小部件,而是允许配置或样式化该小部件,例如scaffloid。

在其中添加新行并按下Ctrl+Space,可以看到支持的多种参数

注:Ctrl+Space用于触发代码补全、智能提示等功能,这个快捷键在某些操作系统或输入法设置下可能与系统功能(如输入法切换)产生冲突,导致无法正常工作,可以修改快捷键以解决冲突,我使用的是Ctrl+Alt+Q。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_62

例如背景颜色参数,允许你设置scafflold创建的背景颜色

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_63

现在backgroundcolor参数需要一个color类型的值

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_64

现在你已经了解了类型,知道参数名称前面的内容是类型定义。

color?表示颜色或者为空值null

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_65

颜色值可以使用内置的颜色类或者构造函数来创建。

MaterialApp、Scaffold、Center、Text是小部件,但从技术上讲,这里调用的函数在代码中称为构造函数,这里可以使用color构造函数来创建一个颜色的东西

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_66

也可以使用特殊颜色,colors. 不用加括号,而是用点来访问预定义颜色的列表

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_67

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_68

运行:

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_69

鼠标悬停在颜色上,会有一个颜色选择器,可以用它来更方便的选择一个颜色。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#开发语言_70

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_71

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_72

fromARGB的函数,给它一个颜色类型的值

这里不是内置在dart中的类型,而是由flutter提供的类型。

所有的值都是一个对象。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_73

flutter中的小部件也只是对象。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#开发语言_74

最后,它们是对象,对象是dart中的基本值,

所有其他值最终也是对象,而对象只是内存中的数据结构,在运行app的设备上,这就是dart在内存中保存值的简单方式。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_75

对象是dart中的核心概念,所有的值最终都是对象,有简单的对象,比如‘hello world’这个文本,也有复杂的对象,比如这个颜色对象或小部件对象、materialapp、scaffold。最终,所有都只是由dart管理的内存中的数据结构,这些数据结构也可以一起工作。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_76

例如backgroundcolor需要一个颜色对象,以便在scaffold小部件对象能够接受到该颜色对象,并使用存储在该颜色对象中的颜色信息来制作该用户界面的背景颜色,所以都是对象。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#开发语言_77

小部件也只是对象,只是flutter中特殊类型的对象,

所有的这些对象都在一起工作,将最终的用户界面带到屏幕上。

使用flutter构建app时,总是会有许多对象一起工作,比如有嵌套在其他小部件中的小部件,但也有这个颜色对象这样的配置对象由小部件使用。

以上就是添加背景颜色的方法,帮助我们意识到dart应用程序中对象的重要概念。

十三、使用配置对象(非部件对象)

现在不能用背景颜色来实现,而且scaffold也没有其他参数可以设置一个渐变背景。

可以在scaffold和center之间添加另一个新的小部件,右键单击center并重构来包装center,从而也隐含的包装text。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_78

用容器来包装它,这是flutter提供的一个小部件。它对于配置样式和布局设置非常有用。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_79

添加后得到的错误

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_80

container它不支持设置为const,不能将这个小部件树中更高的一些父部件设置为const。

蓝色波浪线告诉我们没必要设置容器,因为不配置容器没有任何改变。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_81

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#开发语言_82

ctrl+space,容器部件提供了一个装饰参数,允许添加各种装饰到容器,也就是容器中的子元素。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_83

现在decoration想要一个decoration的参数,可以用内置的BoxDecoration构造函数

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#开发语言_84

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_85

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_86

BoxDecoration类型

调用BoxDecoration函数来构造BoxDecoration对象,还支持各种可以设置的参数。例如gradient梯度参数,然后需要一个gradient类型的值

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#开发语言_87

例如LinearGradient,这是另一个创建线性梯度的构造函数,它也是Gradient类型,这个LinearGradient需要更多的参数,

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_88

我们现在做的通常会将小部件或配置对象嵌套在一起,以便一起运行来提供所需的整体用户界面。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_89

十四、泛型,列表和添加渐变颜色

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_90

鼠标悬停在colors这个参数上面,可以看到List,意味着它需要一个值列表,不仅仅是一个值,而是多个值,这就是dart中的列表,多个值的集合。这里颜色参数的类型定义是一种特殊的dart语言,泛型类型。泛型类型只是一种与其他类型一起工作的类型,但对于可以提供的确切类型是灵活的。比如,list是内置在dart中的一种非常灵活的类型,根据你的用例,可以拥有其他对象的字符串列表,当定义列表的类型时,尖括号之间的类型定义了列表中可能存在的值的类型。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_91

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#开发语言_92

设置const,dart可以存储这些对象这些值并重用,如何在代码其他地方使用,以利用这种内存使用优化,提高app的性能。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_93

十五、如何配置小部件和对象

渐变默认是从左到右,现在我想要左上角到右下角的渐变,可以向LinearGradient添加更多的参数来实现。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_94

可以通过设置坐标

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_95

或者不使用坐标,使用.表示法来访问一些预定义的值

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_96

如何知道这些预定义值的用法,

第一种:需要提供一个值时,按下建议快捷键(ctrl+space),我这里自定义为ctrl+alt+Q。可以获取一些建议,建议菜单非常智能,基本上前三个已经是有帮助的建议。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_97

第二种,查看官方文档

搜索正在使用小部件的名称,flutter LinearGradient

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_98

在官网文章可以知道使用该小部件货配置对象或其他任何内容的更多信息

十六、练习文本样式

现在已经开始使用一些样式选项,现在来设置文本的样式。设置文本的颜色和大小。

巧用帮助快捷键

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_99

如果想设计一些东西或者改变一些小部件的配置,第一步先看看是否有一些参数可以设置。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#开发语言_100

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#开发语言_101

十七、自定义小部件,为什么需要它们

代码越来越多,构建flutter app时通常将大部件树分开并构建自己的部件,将代码拆分为多个较小的可能可重复使用的构建块,一般来说,涉及到分解小部件树和提取自定义小部件没有一种正确或错误的方法,取决于你想把哪些小部件放入自定义小部件。

这里可以把Container容器部件放入自定义部件,使用这个容器及其所有设置和所有子部件,选中的这部分放到一个单独的小部件,因为可以使用这个容器有一个背景渐变应用到app的其他地方,这样我们就有了可重用的预购容器,这里可能只使用一次,但更大的app中可能有多个屏幕,在不同的屏幕或app的不同部分重用某些小部件。即使没有重用,拆分小部件树将Container放入一个单独的小部件也可以提高整体代码的可读性和可维护性。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_102

如何将其放入一个单独的小部件中,需要使用dart中的内置类class关键字来创建一个类。

十八、理解类

小部件是对象,而对象是内存中的这些数据结构。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_103

不仅小部件是对象,所有值的类型也是对象。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_104

因此所有值的类型也是内存中的这种数据结构。

这就是为什么对象概念是dart中的一个关键概念。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_105

类与对象的概念密切相关。

理解dart是一种面向对象的语言。因为每个值都是一个对象。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_106

一些简单的值,如文本或数字,但代码中也有更复杂的值,比如小部件,配置对象。

比如允许配置渐变的LinearGradient对象或单个颜色的对象。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_107

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_108

这些更复杂的值是在类的帮助下创建的,dart中的类是对象的蓝图。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_109

为什么需要这样的蓝图?

对象是内存中的数据结构,那这些数据结构里面有什么?答案是数据,即变量或属性,例如登陆用户的用户名或者渐变所选的颜色;还有函数或在对象上下文中通常称为方法。所以对象是组织数据和分离逻辑。处理某些数据的逻辑通常与该数据位于同一对象中,而不是位于代码中的其他对象或其他位置。哪个对象提供哪些功能取决于对此对象的定义。这就是类重要的地方,有了类,你就定义类它。定义在运行时创建对象时将存储哪种类型的数据,并定义哪些额外的函数(方法)可以存储在这样的对象中。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_110

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_111

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_112

这些东西都有类作为blueprints。

正如官方文档看到的那样,这些都是flutter中内置的蓝图,可以在代码中使用它们来创建基于这些蓝图的对象。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_113

所以在代码中,最终使用的是类和它们的构造函数。

当app在设备上运行,代码从上到下执行,实际的对象被创建并存储在内存中。

随意这些内置的小部件,配置对象,最终都是类,通过像函数一样执行,将其转换为对象。通过调佣它们的构造函数,这个过程也称为类实例化或对象实例化。正在实例化一个类,正在创建一个基于类的对象,这就是自定义小部件也是类的原因。内置的小部件被定义为类,还可以将自定义小部件定义为类。

十九、构建自定义小部件

现在知道类所有的东西都是对象,并且这些对象都是基于类构建的。

类名应该遵循一般规则,并且还应该描述类的内容。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_114

类可以扩展其他类,可以从其他类继承功能、数据和逻辑,通过extends关键字来完成,dart中的内置关键字。

继承StatelessWidget,来自flutter框架的类。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_115

StatelessWidget自动为GradientContaine这个类添加大量逻辑和数据,无需在花括号之间编写任何内容。它添加了flutter所需的大量数据和逻辑,以便将其用作小部件并将其添加到Ui中。

没有在自己的类中实现我应该实现的所有内容,缺少一个名为build的方法。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_116

把函数添加到类中,把这些函数称为方法。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_117

绑定这个类和这个构建方法返回一个Widget,函数名前面的是函数的返回值类型

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_118

还应该在构建方法前添加一个注释,override,明确表明覆盖了StatelessWidget的方法。

除了添加类型和添加重写外, build还必须接受参数。

花括号中间添加函数体,要做的是返回一个小部件,应为build的返回类型是Widget

void也是函数的返回类型,内置在dart中的一个特殊值,意味着没有任何要返回的类型

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#开发语言_119

在应该返回值的函数或方法内部,使用return关键字+想要返回到值。当一个函数或方法使用return关键字返回一个值时,该值将在调用该函数的地方可用。

返回Container小部件及其所有配置和子小部件。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_120

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_121

二十、使用构造函数

公共小部件的构造函数应该有一个key参数

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_122

通常不需要添加构造函数,会自动得到一个,但如果要在创建这个小部件的时候添加一些额外的设置或配置,必须添加自己的构造函数。

只需要重复类的名称,像一个方法一样添加,只是没有返回值。在这里可以做一些初始化工作。

用两个正斜杠添加注释文本,注释文本不会被解释为代码,但可以帮助其他开发人员理解代码。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_123

通常不需要添加花括号

函数中通过花括号来接受参数

要将key这个参数转发给StatelessWidget,可以在构造函数名和圆括号后面加一个冒号,就可以做一些变量初始化的工作。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_124

通过内置在dart中 关键字super,像函数一样执行来访问你继承的父类,把StatelessWidget中命名的参数key设置为构造函数GradientContainer中的参数key

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_125

dart也提供了一个快捷方式

super.key,接受一个名为key的命名参数,并将自动转发给父类

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_126

常量构造函数

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_127

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_128

用自己的构造函数自定义自己的类时,在前面加const,以告诉dart这是一个可以优化的类,可以存储在内存中以便重用

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#开发语言_129

二十一、跨文件拆分代码

除了构造函数,在使用类时还应该将它们放入单独的文件。以保持每个文件袋可读性和可维护性,使文件相对精简,不会包含无止境的代码量。

在lib文件夹添加一个新文件,命名gradient_container.dart。

遵循命名方式,所有的小写多个单词,用_来分割

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_130

这些部件时未知的,在未导入flutter包时会报错。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_131


Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_132

dart不会自动扫描和连接项目中的所有文件,必须使用import关键字来考虑文件之间的任何连接。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_133

二十二、练习创建自定义小部件

将文本样式小部件创建自定义小部件

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_134

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_135

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_136

二十三、引入变量

什么是变量?

变量是数据容器,在var关键字的帮助下创建,然后是赋值运算符等号,然后是应该存储的值。定义一次,在代码的任何地方多次使用。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_137

在渐变容器中,在开头定义对齐方式,在文件开头完成,就不用深入到小部件树中。

变量名以小写字符开头

变量的值可以可变,不能保证它是稳定的,所以在BoxDecoration前我们不能告诉dart可以缓存和重用该值,需要去掉const,因为这些变量没有锁定,可能会发生变化,重复使用此值是不安全的,dart可能会意外的重复使用过时的值

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_138

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_139

二十四、变量和类型-结合两个关键概念

变量也有类型

dart能推断出变量的类型

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_140

如果最初没有赋值,dart不知道这个变量的类型,推断的类型将是动态类型(dynamic),dart中的一种特殊类型,会接受所有值类型。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_141

通常要避免这种情况,没有类型信息可能会导致app的错误,dart无法确保不会在错误的地方使用错误的类型。

在最初没有赋值的情况下,应将var关键字替换为存储在该变量中的类型的名称。?表示可以为null

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_142

二十五、final & const -特殊类型的变量

有时候一些变量永远不会改变

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#开发语言_143

final是一个内置的关键字,意味着这个数据容器永远不会接受新值。

在有多个开发人员在代码上工作的团队中,尽可能的限制,确保一些同事不会意外的覆盖整个项目代码中其他地方的某个变量值。

实际上final是const的另一种用法,const可以创建常量变量或常量数据容器,几乎和final一样,const也确保类你不能重新分配这些变量。

不同的是,const告诉dart是常量,意味着只是在编译代码时被锁定。

但是如果是需要调用一个函数动态计算所需要的对齐,在app运行时执行此函数以获取实际对齐值,这个时候就用final,之后不会重新分配变量,但它不是编译时常量,在编译此代码时,getAlignment可能返回到值还不知道,只有在执行代码时才知道

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_144

二十六、实例变量(属性)和可配置的小部件

使用变量特性来提高代码的可重用性,通过动态接收输入值来调整StyledText这个类,使其更易于重用。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_145

重用StyledText小部件时,总是会输出hello world。现在把输出的文本变成动态。

在GradientContainer小部件使用StyledText小部件时可以设置,小部件应该能从外部接受数据,通常都做法。从GradientContainer小部件内部将数据传递到StyledText小部件中

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_146

在花括号里面输入更多的命名参数,或者在花括号前面添加位置参数

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_147

添加位置参数,加上string参数类型

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#开发语言_148

如何使用这个位置参数?并不能在类中的其他方法直接使用,虽然在同一个类中名,但它们时相互分离的

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_149

必须添加一个类变量,一个属性到这个类中

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_150

确实有了这个变量,但这个变量仍然没有设置为作为位置参数接收的值,可以这样:

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_151

DART给了一种快捷方式,这是一个常见的模式,在参数上接受一个值,并希望将其存储在该类的变量中,在自己的类中接收、存储和使用值。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_152

this.text,查找一个名为text的变量(自动在类中查看一个同名的变量),并设置它等于这里接受到的参数值,这个构造函数接受的第一个参数,this时dart提供的关键字,这个关键字在类内部使用,用来引用类本身或者引用基于类构建的对象。在这里可以使用它来告诉dart我们想要访问这个类中定义的文本变量。

this.text告诉dart不只是想接受这个text位置参数,而是它应该自动映射到一个同名的类变量

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_153

在变量类型前面添加final,任然希望清楚哪种类型的值将存储在这里,明确这只会被接收到的参数设置一次,并且此后不会被更改,一旦初始化,就可以保证始终是同一个对象,可以被dart缓存和重用,这就是接收参数并存储它们的方式。

在属于这些类的变量和基于这些类的对象中,实例化变量,重用不同的文本值的StyledText。以便文本本身不再在StyledText中硬编码。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_154

二十七、练习可重用的部件和构造函数

让GradientContainer更灵活,将颜色作为参数传递给GradientContainer

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_155

方式一:位置参数

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_156

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#开发语言_157

方式二:命名参数

默认情况下,命令参数是可选的,添加required表示不可选

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_158

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_159

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#开发语言_160

方式三:接收两种单独的颜色

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_161

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#开发语言_162

二十八、显示图像和使用多个构造函数

目标是有一个按钮,可以按下它来掷骰子

下一步在屏幕上显示一些骰子图像

将图像文件添加到项目中

新建assets文件夹,再新建images子文件夹,把图像文件拖进来

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_163

为了在代码中使用,还必须配置pubspec.yaml

找到注释掉的这部分

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#开发语言_164

指定包含图像的相对路径

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_165

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_166

Image.asset(),使用资源构造函数

使用内置在dart中的一个特性,可以在给定的类中定义多个构造函数。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_167


Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_168


Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_169


Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_170

二十九、添加按钮和使用函数作为值

添加一个按钮,可以按下滚动骰子

Center小部件仅仅有一个子部件已经不够了

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_171

Center只有child这个参数是小部件,其他参数不需要小部件

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#开发语言_172

想在这里提供多个小部件作为子部件该怎么办?

需要Column()列小部件,在使用flutter时使用很多

Column小部件允许呈现多个小部件,多个小部件彼此垂直

还有个Row()行小部件,多个小部件彼此水平相邻

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_173

Column()中的children参数接收一个列表,一个小部件列表

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_174

因此,可以把图像移到列表

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_175

再在图像下方显示按钮

按钮时非常常见的小部件类型,flutter支持三种不同的主按钮

有一个凸起的按钮,ElevatedButton,用于显示一个有背景色和轻微阴影的按钮

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_176

轮廓按钮,OutlinedButton,用于显示一个没有背景颜色但有边框的按钮

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_177

文本按钮,TextButton,用于显示一个只有一些可按文本的按钮

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_178

有两个必须的参数,onPressed点击时要做的事情,类型是函数或是null作为值,child参数接收另外一个小部件,通常这里是文本小部件,保存应该在按钮上显示的文本

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_179

DART中的函数也只是对象,可以把函数作为一个值来传递。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_180

第一种方式,通过匿名函数,它没有名称,这个函数是在需要函数的地方定义的,这样它就可以作为值提供给onPressed,当onPressed时,该函数由TextButton内部调用,这个函数只能在这里使用,不能在其他地方使用,这就是为什么它没有名字。

在花括号{}之间,可以定义任何你想要的代码,当这个函数被调用的时候这些代码被执行

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_181

第二种方式是定义一个方法,例如,在所有的构造函数和这些变量之后,可以是一个叫rollDice的方法。通过提供一个名称和一个返回值,在本例中是void,因为onPressed需要一个不返回任何内容的函数

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_182

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_183

现在可以使用这个函数名,并将其作为这里的参数值

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_184

保存所有内容并重新加载

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_185

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_186

三十、按钮样式和填充

Column widget默认占用所有可用的垂直空间,不占用所有的可用垂直空间可以通过在Column上 设置另一个参数来完成,mainAxisSize

有两个可以使用的预定义值,默认为max,以占用尽可能多的空间,这里需要min

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_187


Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_188

保存,它会垂直居中

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_189

接下来是按钮的样式,可以通过向TextButton添加style参数来实现,

style参数应写在child参数前面,并不是技术上需要这样做,而是因为这是flutter推荐的模式之一:总是把widget参数放在最后。

例如可以设置foregroundColor(前景色)以更改默认文本颜色,因为TextButton(文本按钮)的前景色是最终的文本颜色。

还可以添加一个单独的textStyle(文本样式),然后使用TextStyle()构造函数的文本样式对象,用它来设置字体的大小为28

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_190

有了这些,这个文本就更大更白了

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_191

现在我只想有更多的间距在这个图像和这个按钮之间,有两种主要的方法来做到这一点。

第一种是在这个文本按钮(TextButton)上添加一些填充,在TextButton.styleFrom函数中通过设置填充(padding)来完成操作。

填充简单的来说就是小部件内部小部件内容和小部件边界之间的一些间距。

这样一个对象可以使用EdgeInsets构造函数来创建。

例如EdgeInsets.all,向所有方向添加一定量的填充,也可以使用EdgeInsets.only(top: 20),传递top参数只在顶部添加填充,使用const转换为常量值

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_192

这个按钮顶部会有更多的空间

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_193

第二种方式,先注释掉这个,然后在图像(Image)和按钮(TextButton)之间添加一个额外的小部件(widget):SizedBox,它创建一个特定大小的盒子,可以在SizedBox()里面添加一个子部件(child),也可以设置高度和宽度

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_194

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#开发语言_195

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_196

它实际上只是占用了那个空间,而没有在屏幕上显示任何东西,这也是SizedBox和其他widget之间的一个重要区别,例如Container(容器)和大多数其他widget(小部件)只是采用他们所需要的宽度和高度来适应他们的内容,例如,Text widget(文本小部件)的高度和宽度与在屏幕上显示文本所需的高度和宽度相同。

使用SizedBox可以显示设置特定的高度或宽度,然后将高度或宽度设置为固定值。

三十一、有状态小部件介绍

如果只是有一个接受一些输入值然后输出一些小部件的小部件,那可以用StatelessWidget,但是如果你有一个widget,其中有一些数据可以在内部更改,并且这些数据的更改会影响渲染的UI,就像这里我们想要在屏幕上显示的图像在我们自己的小部件中取决于这个活动的骰子图像变量,就应该将其创建为一个有状态的小部件(StatefulWidget)。

StatefulWidget,顾名思义,允许我们管理它们内部的状态,而状态只是可能随时间变化的数据,并且应该影响呈现的UI。因此,如果数据发生变化,用户界面也应该发生变化。

这里可取的做法是将这个widget分成单个单独的widget,一个是StatelessWidget,还有个是StatefulWidget,其中包含Image和TextButton。以保持整个代码的组织性。

添加一个新文件,命名为dice_roller.dart

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_197

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_198

现在这个类class DiceRoller,它扩展了有状态小部件tatefulWidget,现在的定义方式与我们之前为StatelessWidget所做的不同,这里不添加Widget build方法,在这里必须添加一个createState() {}方法,像build一样,还应该在这里添加 @override注释,这基本上是我们被迫实现的另一个方法,因为我们在这里扩展了有状态小部件。

现在createState在这里不接受值,但它实际上返回一个值,它返回一个状态对象State,这个一个内置在flutter中的类型,由flutter提供,像前面的list这样的状态是一个通用的值类型。因此,必须添加尖括号<>,以告知DART将在这里管理哪种状态(State)。这里应该是骰子小部件的骰子类的状态(class DiceRoller ),因此,在<>尖括号之间传递的值应该是类名,在这个创建状态方法(createState)的主体中,必须返回(return)这样一个状态值(State),

这个值是用另一个类创建的,使用有状态小部件(StatefulWidget)时,将始终使用两个类,添加第二个类,通常是以下划线开始,下划线在DART中有特殊含义,意味着这个类是私有的,只能在该文件中使用,即使将此文件导入到另一个文件中,该文件也无法访问到此处的此状态类。原因是这个状态类(class _DiceRollerState)只在内部被这个骰子小部件类(class DiceRoller)使用。

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_199

setState这个函数告诉flutter,它应该重新执行这个状态的构建函数

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_200

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_201

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_自定义_202


Flutter完整开发指南 | Flutter&Dart – The Complete Guide_#flutter_203

三十二、生成随机数,完成摇骰子效果

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_应用程序_204

改进优化代码,避免每点击一次都创建一个新的对象,避免内存中冗余的对象创建和删除。以提高效率

Flutter完整开发指南 | Flutter&Dart – The Complete Guide_flutter_205

自此完成了摇骰子的开发。

三十三、总结

DART不仅是面向对象的,而且类型也很重要,Dart是一种类型安全的语言,使用的所有的值都是特定的类型。

构建自定义小部件时,主要有两种自定义小部件,无状态和有状态小部件,区别在于无状态小部件没有内部更改数据,有状态小部件支持更改内部数据更新UI。

无状态小部件和有状态小部件之间的一个关键区别是,对于有状态小部件,实际上创建了两个类,一个小部件类和一个状态类,这两个类一起工作。