Flutter基础
1. Flutter 架构概览
Flutter 是一个跨平台的 UI 工具集,它的设计初衷,就是允许在各种操作系统上复用同样的代码,例如 iOS 和 Android,同时让应用程序可以直接与底层平台服务进行交互。如此设计是为了让开发者能够在不同的平台上,都能交付拥有原生体验的高性能应用,尽可能地共享复用代码的同时包容不同平台的差异。
在开发中,Flutter 应用会在一个 VM(程序虚拟机)中运行,从而可以在保留状态且无需重新编译的情况下,热重载相关的更新。对于发行版 (release) ,Flutter 应用程序会直接编译为机器代码,或者针对 Web 平台的 JavaScript。 Flutter 的框架代码是开源的,遵循 BSD 开源协议,并拥有蓬勃发展的第三方库生态来补充核心库功能。
而Fair是为Flutter设计的动态化框架,通过Fair Compiler工具对原生Dart源文件的自动转化,使项目获得动态更新Widget Tree和State的能力。
创建Fair的目标是支持不发版(Android、iOS、Web)的情况下,通过业务bundle和JS下发实现更新,方式类似于React Native。与Flutter Fair集成后,您可以快速发布新的页面,而无需等待应用的下一个发布日期。Fair提供了标准的Widget,它可以被用作一个新的动态页面或作为现有Flutter页面的一部分,诸如运营位的排版/样式修改,整页面替换,局部替换等都可以使用。
Flutter 被设计为一个可扩展的分层系统。它可以被看作是各个独立的组件的系列合集,上层组件各自依赖下层组件。组件无法越权访问更底层的内容,并且框架层中的各个部分都是可选且可替代的。从下到上分为三层,依次为:Embedder、Engine、Framework:Embedder:
Embedder:操作系统适配层,实现了渲染 Surface 设置,线程设置等。
Engine:是 Flutter 的核心,它主要使用 C++ 编写,并提供了 Flutter 应用所需的原语。当需要绘制新一帧的内容时,引擎将负责对需要合成的场景进行栅格化。它提供了 Flutter 核心 API 的底层实现,包括图形(通过 Skia)、文本布局、文件及网络 IO、辅助功能支持、插件架构和 Dart 运行环境及编译环境的工具链。
Framework :是一个用 Dart 实现的 UI SDK,包含了动画、图形绘制和手势识别等功能。开发者可以通过 Flutter 框架层与 Flutter 交互,该框架提供了以 Dart 语言编写的现代响应式框架。它包括由一系列层组成的一组丰富的平台,布局和基础库。所以我们先分析下Dart的基础知识。
2. Dart 基础
Flutter之所以采用Dart语言来进行Flutter应用开发,而并非Java、Javascript这类热门语言,这是Flutter团队对当前热门的10多种语言慎重评估后的选择。因为Dart囊括了多数编程语言的优点,它更符合Flutter构建界面的方式。
2.1 Dart语言概述
在Dart中,一切都是对象,所有的对象都是继承自Object;
Dart是强类型语言,但可以用var或 dynamic来声明一个变量,Dart会自动推断其数据类型,dynamic类似c#;
Dart支持顶层变量,也支持类变量或对象变量;
Dart没有public protected private等关键字,如果某个变量以下划线(_)开头,代表这个变量在库中是私有的;
Dart 工具可以显示 警告 和 错误两种类型的问题。警告表明代码可能有问题但不会阻止其运行。错误分为编译时错误和运行时错误;编译时错误代码无法运行;运行时错误会在代码运行时导致异常。
标识符 可以以字母或者下划线 (_) 开头,其后可跟字符和数字的组合。
2.2 数据类型
Dart 语言支持内置类型:
Number (int, double)
String (String)
Boolean (bool)
List (也被称为 array)
Set (Set)
Map (Map)
Runes (常用于在 Characters API 中进行字符替换)
Symbol (Symbol)
The value null (Null)
2.2.1 变量:
下面的示例代码将创建一个变量并将其初始化:
var name = 'Bob';
变量仅存储对象的引用。这里名为 name 的变量存储了一个 String 类型对象的引用,“Bob” 则是该对象的值。name 变量的类型被推断为 String,但是你可以为其指定类型。如果一个对象的引用不局限于单一的类型,可以将其指定为 Object(或 dynamic)类型。
Object name = 'Bob';
也可以指定类型:
String name = 'Bob';
2.2.2 数据类型:
Number:Dart 支持两种 Number 类型:int 和 double,分别表示整型和浮点型。int 和 double 都是 num 的子类。整数是不带小数点的数字,下面是一些定义整数字面量的例子:
var x = 1;
var hex = 0xDEADBEEF;
var exponent = 8e5;
如果一个数字包含了小数点,那么它就是浮点型的。下面是一些定义浮点数字面量的例子:
var y = 1.1;
var exponents = 1.42e5;
String:Dart 字符串(String
对象)包含了 UTF-16 编码的字符序列。可以使用单引号或者双引号来创建字符串:
var s1 = '使用单引号创建字符串字面量。';
var s2 = "双引号也可以用于创建字符串字面量。";
var s3 = '使用单引号创建字符串时可以使用斜杠来转义那些与单引号冲突的字符串:'。';
var s4 = "而在双引号中则不需要使用转义与单引号冲突的字符串:'";
Boolean:Dart 使用 bool 关键字表示布尔类型,布尔类型只有两个对象 true 和 false,两者都是编译时常量。
bool isTrue = true;bool isFalse = false;
List:数组 (Array) 是几乎所有编程语言中最常见的集合类型,在 Dart 中数组由 List 对象表示。通常称之为 List。
var list = [1, 2, 3];
Set:在 Dart 中,set 是一组特定元素的无序集合。 Dart 支持的集合由集合的字面量和 Set 类提供。
var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
Map:通常来说,Map 是用来关联 keys 和 values 的对象。其中键和值都可以是任何类型的对象。每个 键 只能出现一次但是 值 可以重复出现多次。 List。
var gifts = {
// Key: Value
'first': 'partridge',
'second': 'turtledoves',
'fifth': 'golden rings'
};
3. Flutter 基础
在 Flutter 中,一切用于显示的都是 Widget 。Widget 是Flutter的基础,Widget 分为 有状态 和 无状态 组件两种。无状态就是创建之后就不会改变,一直保持初始时候的状态,常见的有Container、ScrollView等。而有状态的 Widget 当数据更新时,其实是绘制了新的 Widget,常见的有CheckBox、AppBar、TabBar等。其中,这两种widget都是继承自Widget父类。
3.1 Widget介绍
Flutter 从 React 中吸取灵感,通过现代化框架创建出精美的组件。它的核心思想是用 widget 来构建你的 UI 界面。 Widget 描述了在当前的配置和状态下视图所应该呈现的样子。当 widget 的状态改变时,它会重新构建其描述(展示的 UI),框架则会对比前后变化的不同,以确定底层渲染树从一个状态转换到下一个状态所需的最小更改。
Flutter 自带了一套强大的基础 widgets,下面列出了一些常用的:
Text
Text widget 可以用来在应用内创建带样式的文本。
Row, Column
这两个 flex widgets 可以让你在水平 (Row
) 和垂直(Column
) 方向创建灵活的布局。它是基于 web 的 flexbox 布局模型设计的。
Stack
Stack widget 不是线性(水平或垂直)定位的,而是按照绘制顺序将 widget 堆叠在一起。你可以用 Positioned
widget 作为Stack
的子 widget,以相对于 Stack
的上,右,下,左来定位它们。 Stack 是基于 Web 中的绝对位置布局模型设计的。
Container
Container widget 可以用来创建一个可见的矩形元素。 Container 可以使用 BoxDecoration 来进行装饰,如背景,边框,或阴影等。 Container
还可以设置外边距、内边距和尺寸的约束条件等。另外,Container
可以使用矩阵在三维空间进行转换。
Widget的生命周期:
在 StatefulWidget 上调用 createState() 之后,框架将新的状态对象插入到树中,然后在状态对象上调用 initState()。 State 的子类可以重写 initState
来完成只需要发生一次的工作。例如,重写 initState
来配置动画或订阅平台服务。实现 initState
需要调用父类的 super.initState
方法来开始。
当不再需要状态对象时,框架会调用状态对象上的 dispose() 方法。可以重写dispose
方法来清理状态。例如,重写 dispose
以取消计时器或取消订阅平台服务。实现 dispose
时通常通过调用 super.dispose
来结束。
3.2 Layout
Flutter 布局的核心机制是 widget。在 Flutter 中,几乎所有东西都是 widget —— 甚至布局模型都是 widget。你在 Flutter 应用程序中看到的图像,图标和文本都是 widget。此外不能直接看到的也是 widget,例如用来排列、限制和对齐可见 widget 的行、列和网格。
举个例子,创建一个 Text widget:
Text('Hello World'),
创建一个 Image widget:
Image.asset(
'images/lake.jpg',
fit: BoxFit.cover,
),
创建一个 Icon widget:
Icon(
Icons.star,
color: Colors.red[500],
),
将 Text widget 添加进 Center widget:
const Center(
child: Text('Hello World'),
),
一个 Flutter app 本身就是一个 widget,大多数 widgets 都有一个 build() 方法,在 app 的 build() 方法中实例化和返回一个 widget 会让它显示出来。
lib/main.dart (MyApp)
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter layout demo',
home: Scaffold(
appBar: AppBar(
title: const Text('Flutter layout demo'),
),
body: const Center(
child: Text('Hello World'),
),
),
);
}
}