Flutter 知识点
Flutter:一个移动应用开发框架,它使用 Dart、C++、Skia 开发,对外提供了完全不依赖系统平台的 Widget 的能力,只通过自绘图形的方式工作,具有极其优秀的跨平台性。目前已经支持了 iOS、Android、Fuchsia。
macOS 下,安卓模拟器的进程名为:sdkqemu-system-i386,可在任务管理器强行关闭。
如果提示:Please configure Android SDK,需要将 ANDROID_HOME 环境变量设置为相应的 SDK 安装目录
构建UI界面的逻辑在build方法中
Scaffold
是Material库中提供的页面脚手架,它包含导航栏和Body以及FloatingActionButton(如果需要的话)
路由(Route)在Android中通常指一个Activity,在iOS中指一个ViewController。
在原生开发中,Android使用Gradle来管理依赖,iOS用Cocoapods或Carthage来管理依赖。
而 Flutter 使用配置文件 pubspec.yaml(位于项目根目录)来管理第三方依赖包。
在构建期间,Flutter将asset放置到称为 asset bundle 的特殊存档中,应用程序可以在运行时读取它们(但不能修改)。
声明分辨率相关的图片 assets:
AssetImage 可以将asset的请求逻辑映射到最接近当前设备像素比例(dpi)的asset。为了使这种映射起作用,必须根据特定的目录结构来保存asset。
注意,AssetImage 并非是一个widget, 它实际上是一个ImageProvider,有些时候你可能期望直接得到一个显示图片的widget,那么你可以使用Image.asset()方法。
依赖包中的资源图片
要加载依赖包中的图像,必须给AssetImage提供package参数。
例如,假设您的应用程序依赖于一个名为“my_icons”的包,它具有如下目录结构:
…/pubspec.yaml
…/icons/heart.png
…/icons/1.5x/heart.png
…/icons/2.0x/heart.png
…etc.
然后加载图像,使用:
new AssetImage('icons/heart.png', package: 'my_icons')
或
new Image.asset('icons/heart.png', package: 'my_icons')
注意:包在使用本身的资源时也应该加上package参数来获取。
Dart分析器大量使用了代码中的类型注释来帮助追踪问题。我们鼓励您在任何地方使用它们(避免var、无类型的参数、无类型的列表文字等),因为这是追踪问题的最快的方式。
可以使用 debugger()
语句插入编程式断点。要使用这个,你必须添加 import 'dart:developer';
到相关文件顶部;debugger()语句采用一个可选when参数。
微任务通常来源于Dart内部,并且微任务非常少。
值得注意的是,我们可以通过Future.microtask(…)方法向微任务队列插入一个任务。
在事件循环中,当某个任务发生异常并没有被捕获时,程序并不会退出,而直接导致的结果是当前任务的后续代码就不会被执行了,也就是说一个任务中的异常是不会影响其它任务执行的。
Flutter 中真正代表屏幕上显示元素的类是 Element,Widget 只是 Element 的配置数据。并且一个Widget可以对应多个Element。
Key: 这个key属性类似于React/Vue中的key,主要的作用是决定是否在下一次build时复用旧的widget,决定的条件在canUpdate()方法中。
didChangeDependencies()、didUpdateWidget()
- didChangeDependencies():当State对象的依赖发生变化时会被调用;例如:在之前build() 中包含了一个InheritedWidget,然后在之后的build() 中InheritedWidget发生了变化,那么此时InheritedWidget的子widget的didChangeDependencies()回调都会被调用。典型的场景是当系统语言Locale或应用主题改变时,Flutter framework会通知widget调用此回调。
- didUpdateWidget():在widget重新构建时,Flutter framework会调用Widget.canUpdate来检测Widget树中同一位置的新旧节点,然后决定是否需要更新,如果Widget.canUpdate返回true则会调用此回调。正如之前所述,Widget.canUpdate会在新旧widget的key和runtimeType同时相等时会返回true,也就是说在在新旧widget的key和runtimeType同时相等时didUpdateWidget()就会被调用。
deactivate()、dispose()
- deactivate():当State对象从树中被移除时,会调用此回调。在一些场景下,Flutter framework会将State对象重新插到树中,如包含此State对象的子树在树的一个位置移动到另一个位置时(可以通过GlobalKey来实现)。如果移除后没有重新插入到树中则紧接着会调用dispose()方法。
- dispose():当State对象从树中被永久移除时调用;通常在此回调中释放资源。
Flutter提供了一套丰富、强大的基础widget,在基础widget库之上Flutter又提供了一套Material风格(Android默认的视觉风格)和一套Cupertino风格(iOS视觉风格)的widget库。要使用基础widget库,需要先导入:
import 'package:flutter/widgets.dart';
由于Material和Cupertino都是在基础widget库之上的,所以如果你的应用中引入了这两者之一,则不需要再引入flutter/widgets.dart了,因为它们内部已经引入过了。
基础widget
- Text:该 widget 可让您创建一个带格式的文本。
- Row、 Column: 这些具有弹性空间的布局类Widget可让您在水平(Row)和垂直(Column)方向上创建灵活的布局。其设计是基于web开发中的Flexbox布局模型。
- Stack: 取代线性布局 (译者语:和Android中的FrameLayout相似),Stack允许子 widget 堆叠, 你可以使用 Positioned 来定位他们相对于Stack的上下左右四条边的位置。Stacks是基于Web开发中的绝对定位(absolute positioning )布局模型设计的。
- Container: Container 可让您创建矩形视觉元素。container 可以装饰一个BoxDecoration, 如 background、一个边框、或者一个阴影。 Container 也可以具有边距(margins)、填充(padding)和应用于其大小的约束(constraints)。另外, Container可以使用矩阵在三维空间中对其进行变换。
Text
- textAlign:文本的对齐方式;可以选择左对齐、右对齐还是居中。注意,对齐的参考系是Text widget本身。本例中虽然是指定了居中对齐,但因为Text文本内容宽度不足一行,Text的宽度和文本内容长度相等,那么这时指定对齐方式是没有意义的,只有Text宽度大于文本内容长度时指定此属性才有意义。
- textScaleFactor:代表文本相对于当前字体大小的缩放因子,相对于去设置文本的样式style属性的fontSize,它是调整字体大小的一个快捷方式。该属性的默认值可以通过MediaQueryData.textScaleFactor获得,如果没有MediaQuery,那么会默认值将为1.0。
- height:该属性用于指定行高,但它并不是一个绝对值,而是一个因子,具体的行高等于fontSize*height。
- fontSize:该属性和Text的textScaleFactor都用于控制字体大小。但是有两个主要区别:
- fontSize可以精确指定字体大小,而textScaleFactor只能通过缩放比例来控制。
- textScaleFactor主要是用于系统字体大小设置改变时对Flutter应用字体进行全局调整,而fontSize通常用于单个文本。
在Flutter中使用字体分两步完成。首先在pubspec.yaml中声明它们,以确保它们会打包到应用程序中。然后通过TextStyle属性使用字体。
按钮:有一个onPressed属性来设置点击回调,当按钮按下时会执行该回调,如果不提供该回调则按钮会处于禁用状态,禁用状态不响应用户点击。
使用自定义字体图标:在Flutter中,使用iconfont.cn上ttf格式的字体文件即可
容器的大小可以通过width、height属性来指定,也可以通过constraints来指定,如果同时存在时,width、height优先。实际上Container内部会根据width、height来生成一个constraints。
Material Design 设计规范中有些是不能自定义的,如导航栏高度,ThemeData只包含了可自定义部分。
如果不想让某个子树响应PointerEvent的话,我们可以使用IgnorePointer和AbsorbPointer,这两个Widget都能阻止子树接收指针事件,不同之处在于AbsorbPointer本身会参与命中测试,而IgnorePointer本身不会参与,这就意味着AbsorbPointer本身是可以接收指针事件的(但其子树不行),而IgnorePointer不可以。
GestureDetector内部是使用一个或多个GestureRecognizer来识别各种手势的,而GestureRecognizer的作用就是通过Listener来将原始指针事件转换为语义手势,GestureDetector直接可以接收一个子Widget。GestureRecognizer是一个抽象类,一种手势的识别器对应一个GestureRecognizer的子类。
在Flutter中自定义Widget有三种方式:通过组合其它Widget、自绘和实现RenderObject。
自绘:Flutter中提供了CustomPaint和Canvas供我们自绘UI外观。
际上Flutter提供的所有Widget最终都是调用Canvas绘制出来的。
通过HttpClient设置的header,对整个httpClient都生效;而通过HttpClientRequest设置的header,只对当前请求生效。
与Future返回单个异步响应不同,Stream类可以随着时间推移传递很多事件。
运行flutter build apk
后,打包文件的路径:build/app/outputs/apk/release/app-release.apk