在 AndroidStudio
中,可以在 External Libraries
下查看存在的 Dart Packages
。如下是一个新建项目存在的内置包。这些包中定义的公开类、方法、对象都可以在代码中使用。其实可以看出各种 Widget
只是 Flutter
框架的一部分,除了组件之外,还有很多其他的包。这里简单讲一下相关包的功能,不详细展开了。
可以说 flutter 包是 Flutter 框架
的核心包,我们在开发中使用的绝大多数类都是这个包中的。包括 组件
、动画
、手势
、绘制
、渲染
、调度器
等
sky_engine 也是一个非常重要的包,内置的数据类型,int、double、bool 、List、Map 等都在 core
中。此外 async
中提供了异步相关的 Future
、Stream
、Timer
等重要类。collection
提供了集合 HashMap
、Queue
、SplayTreeSet
、LinkedList
等结构容器。io
提供文件操作的功能,convert
用于转换相关,ffi
用于调用 C 代码。
path 包中定义了很多文件路径、URL 操作的方法。也比较常用。
对正则的使用进行封装,可以更方便地扫描字符串,对于字符串的处理非常有价值。
Dart 包仓库在 pub.dev/,比如我现在想使用一个 equatable
包,可以在网站上查看到最新的版本。在 项目的 pubspec.yaml
的 dependencies
节点下配置即可。
---->[pubspec.yaml]----
dependencies:
flutter:
sdk: flutter
equatable: ^1.2.6 # 配置包
然后执行 Pub get
,你就可以在 Dart Packages
下看到 equatable
包。
然后通过 import
关键字就可以将包导入,在相应源码文件中使用包中定义的类。
import 'package:equatable/equatable.dart';
class Point extends Equatable{
final double x;
final double y;
Point(this.x, this.y);
@override
List<Object> get props => [x,y];
}
复制代码
比如现在我想创建一个 calculator
的包,用于一些换算逻辑的处理。在 Flutter 中通过 File -> New -> New Flutter Project...
打开创建界面,选择第三个 Flutter Package
。
然后填写项目的信息,如下:
这样,我们就创建好了一个包。可以在 lib
中书写代码,提供给用户使用。
library calculator;
class Calculator {
/// 通过 [height] 身高(m) 和 [weight] 体重(kg),获取 BMI 指标
///
static double getBMI(double height, double weight) {
return weight / (height * height);
}
}
复制代码
当你创建有个包时,就意味着你在其中敲代码时,身份是一个创造者
。包里的逻辑再复杂都无所谓,你只要让用户觉得好用,简单,方便就行了。当然,每一个创造者的第一个用户都是他自己
。现在回到刚才的初始项目中,这时你的角色就是 使用者
。那如何使用自己创建的包呢?
第一种方式是通过 通过文件路径引入包
,格式如下。这种方式并不推荐,因为如果写成绝对路径,别人在运行你的项目时,就会找不到包而出现问题。
dependencies:
flutter:
sdk: flutter
equatable: ^1.2.6
# 通过绝对路径引入包
calculator:
path: /Volumes/coder/Projects/Flutter/pkg/calculator
解决方案很简单,可以将包创建在项目内,用相对路径引用。如下在 flutter_base
中创建 calculator
包,就相当于创建了一个模块,代码提交时一并提交即可。如果一个模块相对独立,这样分包的方式可以让项目结构更清晰,想要在另一个项目中复用模块的话,拷贝模块即可。这要比什么都塞在一块要好。
import 'package:calculator/calculator.dart';
Calculator.getBMI(1.8, 70)
如果只是自己使用,可以通过本地引用。但想要分享给别人一起使用,就需要通过网络了。可以将 calculator
包传到 github 仓库中,然后通过 git-url
进行引入,操作如下:
dependencies:
flutter:
sdk: flutter
equatable: ^1.2.6
# 通过路径引入包
calculator:
git:
url: https://github.com/toly1994328/calculator.git
这样在 Dart Packages
中就会自动下载 calculator
的包,并加一个后缀名。
我们可以看到下载的包在如下文件夹下。
使用 git 的方式,包的版本更新会比较麻烦。如果想要维护更新,最好提交到 pub 上。在此之前要做些准备,写好信息 和 LICENSE
。然后通过下面命令进行提交,第一次提交需要身份验证,这里就不展开了。
flutter packages pub publish --server=https://pub.dartlang.org
下面我们通过源码中的 flutter
包来看一下一些要点。下面红框中的 dart
文件在 src
包之外,其本身并没有任何的逻辑处理,只是做了包的定义
和相关文件
的导出,分别对应 library 和 export 关键字
。
这样每个包可以有很多的 library。在导入包时,就不需要一次性将包中所有的文件导入,只是导入对应 library
中的文件。
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
这样我们也可以在 calculator
包中进行类似的处理。
除了导出文件外,也可以导出库,但一个库中的对象非常多,如果指向导出某一部分类、方法、变量,可以使用 show
关键字,表示这些量可见。同理,如果只是某些量想要隐藏,可以使用 hide
关键字。
这两个关键字在 import
和 export
中都可以使用,如下 hide StatelessWidget
时,就无法在该文件中使用 StatelessWidget
。
通过 as
关键字可以给导入的量起别名,这样可以避免名称的冲突,或者在语义上更清晰。比如在 flutter/src/patting/borders.dart
中,引入 math
和 ui
包时使用 as
关键字起别名。
这在使用时就可以通过 别名.量
来使用,如下 ui.lerpDouble
。 这样好处在于 lerpDouble
不会那么突然出现,让读码者知道这是 ui
包内的 lerpDouble
方法,不然可能让人认为是成员方法。
在 flutter
包中,源码文件组织方式是,定义 library
,然后export
各个文件来实现。这样的话,每个份文件都是一个独立的个体,需要引入与自身相关的包。而 part
与 part of
则是源码文件的组织的另一种形式。vector_math
包使用的是 part 和 part of
。
如下,结构比较类似,也是src
外部的文件负责组织源码文件,只不过没有 export
的动作,反而是 import
一些类,然后通过 part
关键字建立与各源码文件的关系。
下面看一下源码中的 Matrix4
,在一开始通过 part of
表示出它是 vector_math
中的一部分。那这有什么优势呢?
如下,在 Matrix4
中可以看到,使用了 math
和 quiver
,这两个名字是在 vector_math
中导入的,在 Matrix4
并未导入。可见 part of
也可将 Matrix4
视为 vector_math
中的部分,在 vector_math
中导入的包可以在子块中使用这样就可以避免每个源码文件都导入相同的东西。
到这里,关于包的几个关键字就讲完了,你应该对 Flutter 的包结构有了更深的了解。当你在使用某个对象时不妨停下想象,这个类是定义在那个包下的哪个文件中的,这样对Flutter 的理解就会更上一个层次。那本篇就到这里,谢谢观看 ~