安装flutter
使用flutter模板即可 会自带dart
参考文档
下载模板后 在vscode中按下ctrl+shift+P并使用Flutter: Select Device选择一个平台 再使用flutter run命令运行项目
项目结构
lib/main.dart是flutter项目的入口 其余文件夹与测试、原生有关 暂时不关心
flutter插件会生成widget树以便于开发
dart语言基础
基本语法
- 在每个语句后写分号 语句块则不用
- 有if-else/for/switch语句
- 可以以这样的方式构造字面量 条件字段/循环添加字段
{
if(a>1)'a' :a,
for (var x in ['a']) 'x': x
}
[
if(a>1) a,
for (var x in ['a']) x
]
包
// dart sdk
import 'dart:xxx';
// 包路径
import 'package:xxx';
// 本地文件
import 'xxx.dart'
引用本地文件时 同文件下可以省略'./'前缀
下载第三方包
在pub.dev寻找第三方包 然后在pubspec.yaml添加相应的依赖 最后执行flutter pub get
项目包
import 'package:project_name/a.dart';
可以索引到lib/a.dart 其中project_name来自pubspec.yaml的name属性
导入导出
包内所有以下划线开头的成员外界无法访问 其余成员自动导出
如果包之间有成员名称冲突 可以将包重命名
import 'xxx' as xxx;
想导出其他包的成员 必须主动导出
export 'xxx';
用于聚合导出
变量和类型系统
- 声明变量时 类型前置
String a = 'a';可以使用var自动获取变量类型 - 基本类型
int整数double浮点数num同时处理整数和浮点数String字符串 用单引号双引号均可 支持用$或${xx}进行变量插值- 使用三引号声明的字符串可以换行
- 使用
r'aa\n'声明的字符串会被视为原始字符串(不能转义/插值)
bool布尔类型- List
List<int>字面量形如[1,2] - Map
Map<String, String>字面量形如{'a':'a'} - Set
Set<String>字面量形如{'a','b'}。注意 Set类型要求值唯一
- 强类型 一般情况变量不可更改 所有类型都继承自
Object包括基本类型 - 使用
is运算符判断类型.可以用于判断任何类型,包括自定义类型 - 使用
as运算符强制声明类型 dynamic代表着编译时不检查类型 而是把问题留到运行时Object表示需要先判断类型再使用nullnull的类型是Null唯一的空值.只有用形如int? a声明的变量可以被赋null.注意 若是List/Set要接受空值 内部数据的类型必须声明为可空- 类型别名
typedef为复杂类型创建可读性高的别名 final关键字表示运行时的不变量,const关键字表示编译时的不变量(不一定是字面量).用final或const修饰正在定义的变量时,可以省略var.
空值处理
dart有完备的空值防备语法
a ?? xx空值合并a!非空断言a?.xx非空可访问a??=在空值时赋值
late关键字
在初始化时不赋值 由开发者确保使用前赋值
函数
函数的定义方式如下
// 按位置传参
// 允许可选参数 不传或者传null都可以
void fn(String a, String? b, String c) {}
// 使用命名参数
void fn({required String a, String? b, String c='a'}) {}
命名参数是推荐的函数定义方式 调用方式为fn(a:'a');.命名参数里 必填参数应当声明为required或者设置默认值
函数也是变量的一种 可以直接赋值 其类型一般形如int add(int,int) 可以使用typedef创建可读性较高的函数类型
可空函数这样调用
fn?.call();
函数具有闭包
可以声明箭头函数 但箭头函数只能指向一个表达式 不能有多行语句
// 箭头函数 必须是单个表达式
var fn = ({required String a, String? b, String c='a'}) => 'a $a';
异步
dart也有事件循环 同样分为同步代码和两个队列 分别为microtask和event queue(类似宏队列) 它们的执行顺序和js一样
用Future对象描述一个将来可能取得的值或完成的行为
// 进入microtask
Future.value(42);
Future.error('error');
Future.microtask((){
// 在microtask创建执行这个函数的任务
})
// 进入event queue
Future.delayed(const Duration(seconds: 1))// 等一秒
Future((){
// 在event queue创建执行这个函数的任务
})
// 使用Future对象 类似js的then catch finally
Future.value(42).then(() {}).catchError(() {}).whenComplete(() {});
使用Completer创建一个手动控制的Future 类似new Promise
import 'dart:async';
final completer = Completer<int>();
// completer.complete(1);
// completer.completeError('a');
// await completer.future;
在异步函数里 可以await一个Future
Future<void> fn() async {
await Future.value(42);
}
同样有try catch finally
类
- 类可以声明属性和函数
- 类函数(包括构造函数)访问类属性不需要this.前缀
- 类函数可以被赋值给其他变量 会自动绑定类实例
- 创建类实例直接
var a = A()即可
构造函数
class A {
// 不经过构造函数 直接初始化
String b = 'b';
String a;
// 构造函数
A(this.a);
// 或者
A({this.a = 'a'});
A({required this.a});
}
如果类属性不能为null则this.a必须出现在构造函数中
如果这一属性不能直接从构造函数中获得 应当将其声明为late
class A {
late String a;
A({required String b}) {
a = 'b $b';
}
}
构造函数可以有多个 并且可以调用其他构造函数
class A {
late String a;
A.withName(this.a);
A() : this.withName('a');
// 调用默认构造函数直接this()即可
}
// 使用具名构造函数
A.withName('a')
继承
使用extends关键字用于继承
class A extends B {
A(String a): super(a){
// xxx
}
//或者 直接初始化父类属性
A(super.key);
}
构造函数后可以跟随初始化列表 在这里调用父类的构造函数
这里不显式调用父类构造函数 则dart会默认调用其无参构造函数
函数重载需要@override
函数或属性会继承父类 可以直接访问 同名的使用super.xxx访问
getter&setter
class A {
String a;
A(this.a);
// 不能同名
get name1 => a;
set name2(String newName) => a = newName;
}
抽象类
只规定属性和类函数 用于被其他类继承
abstract class A {
double get a;
void b();
}
可以在is的右侧用于判断类型
抽象类可以有非抽象函数
minix(混入)
mixin可以为一个类型提供能力 通过with的方式组合到类型里 不改变继承链
可以组合多个minix
minix可以有属性、函数 但不能有构造函数
mixin A {
void doSomething(){}
}
class B with A {
}