Dart基础
如果你有JS
、Java
、Kotlin
、Swift
等语言的基础,入门几乎没啥子难度
程序入口
dart
从main
函数开始运行,国际惯例
void main() {
print("Hello World!");
}
由于dart
中没有private
、public
等修饰符,所以约定俗成下划线开头表示私有。
下面用一个类的声明讲解
/// 声明
class Hello {
/// 私有变量
String _privateName = "私有名称";
/// 公开变量
int age = 18;
/// 私有方法
_privateFunction() {
print("1");
}
/// 公开方法
publicFunction() {
print("1");
}
@protected
refresh() {
}
}
setter/getter
double _progress;
double get progress => _progress;
set progress(double newValue) {
/// 自己的逻辑处理
_progress = newValue;
}
final/const
两者都是声明常量使用,区别是一个是在编译期,一个是运行期。
import
用于导入某些具体类/第三方SDK
的实现
基础数据类型
dart
支持数字、字符串、bool、数组(列表)、集合等数据。
数字
int
取值区间在 ~double
类型为64位的双精度浮点型
方法 | 含义 |
---|---|
isFinite | 是否为有限数字 |
isInfinite | 是否是无穷大 |
isNan | 是否是数字 |
isNegative | 是否为负数 |
sign | 如果数字小于0,返回-1;大于0返回1,如果本身是Nan或者0,返回0 |
isEven | 是否是偶数 |
isOdd | 是否是奇数 |
abs | 绝对值 |
ceil | 返回不小于该数字的最小整数 |
floor | 返回不大于当前数字的最大整数 |
round | 返回最接近当前数字的整数 |
toDouble | 转化为double类型 |
字符串
字符串可以用""
表示也可以用''
表示。
在字符串中引用其他的变量
-
成员变量
"print("age is $age");"
-
成员变量的成员变量、或者其他表达式
print("name is ${jack.nickName}");
字符串可以用 + 号连接
bool
dart
中的if
只支持bool
只,不支持判空处理
String g = null;
/// 不合法
if (g) {}
/// 合法
if(g!=null) {}
集合(列表)
- 有序
- 可重复
List list = [1,2,3,4,5, "6"]; 未指定的类型的情况下,可以插入任意值
List<String> strList = ["a", "b", "c"]; // 指定类型的情况只能插入该类型的值
List list2 = [-1, 0, ...list];
List list3 = null;
List list4 = [10, 11, ...?list3];
方法 | 说明 |
---|---|
generate | 根据数据创建一个表 |
length | 列表长度 |
sort | 排序,根据传入的compare判断条件 |
indexOf | 获取下表,根据传入的条件,正序遍历找到就返回 |
lastIndexWhere | 从后向前遍历,根据传入条件找到第一个返回并结束 |
Set 集合
- 无序
- 不可重复
Set<String> name = {"Jack", "Mark"};
name.add("Lucky");
方法 | 说明 |
---|---|
lookup | 查找某个元素 |
contains | 是否包含某个值 |
difference | 两个集合进行比较,返回不同的元素 |
Map
键值对的方式进行数据的存储,键唯一,值可以不唯一。
未指定value的类型情况下,值可以是任意类型
Map map = {
"age": 19,
"name": "Hello",
"info": {}
};
//add
map['address'] = "";
//put
String name = map['name'];
方法 | 说明 |
---|---|
putIfAbsent | 根据传入的key查看值是否存在,存在就返回,不存在就插入在返回 |
isEmpty | 是否为空 |
isNotEmpty | 是否不为空 |
length | 返回map的长度 |
containsKey | 是否包含某个key |
containsValue | 是否包含某个value |
enum
枚举,这里枚举值的类型是int,默认从0开始,并且不可以设置起始值
enum Style {
normal,
vip
}
常用操作符
-
..
联级操作符
Object obj = Object(); obj ..name="" ..age=18 ..address = "";
-
??
判断前面的值/对象是否为空,为空就是用??后面的值
int a = null; int b = 1; print("${a ?? "hello"}"); // hello print("${b ?? "hello"}"); // 1
-
??=
判断是否已经初始化
int a = 2; a ??= 3; print("$a"); // 2, 如果是 int a = null; 那么结果就是 3
-
~/
整除
print("${5.2 ~/ 3.3 }"); // 1
var和dynamic
var
会自动推导出类型,var
只是语法糖,运行的时候会根据值推到类型
dynamic
表示动态类型,不做任何检测,真正的动态类型
函数方法
dart中的函数声明格式为返回值 函数名(参数列表) 修饰符{ 函数体}
int test(int age, {String name, String address}) async {
await Future.delay(Duration(seconds: 1));
return 1;
}
// int 返回值类型
// test 函数名称
// int age 参数(必填,且顺序固定
// String name 参数 (非必填,顺序不要求
// String address 参数 (非必填,顺序不要求
// async 标记是异步方法
// {}内部就是函数体
类、接口、继承
类
-
abstract class 接口类
内部的函数只用声明就够了
-
class
内部的函数需要实现
接口
dart中没有接口关键字,类也可以作为接口,只需要使用implements实现就好
继承
extends,使用这个修饰。
demo
abstrace class Interface {
void doA();
void doB();
}
class InterfaceClass {
void doC() {}
void doD() {}
}
class Demo implements Interface, InterfaceClass {
void doA() {}
void doB() {}
void doC() {}
void doD() {}
}
mixins
混入,混入是的基础顺序是从右到做依次执行,也就是说最后混入的类,如果遇到同名函数,最优先执行,而且和super方法是否执行有关。
异常
通过try..catch捕获异常,通过throw抛出异常
异常类型 | 说明 |
---|---|
FormatException | 当字符串或某些其他数据没有预期格式,且无法解析活处理时抛出 |
IntergerDivisionByZeroException | 当数字除与0的时候抛出 |
IOException | 输入、输入相关的异常 |
IsolateSpawnException | 无法创建隔离时抛出 |
Timeout | 等待异步结果是,如果发生超时,则抛出 |
Isolate
Dart本身是单线程执行,但还是增加了Isolate提供跨线程的真异步操作。因为在dart线程中不会共享内存,所以也不会存在死锁,从而而导致了Isolate之间的数据只能通过port的端口方式发送接口,所以Isolate也称之为隔离的执行。Dart中提供了Isolate的封装,便于我们使用
Isolate主要在 dart:isolate包中,其中
- Isolate用于dart执行上下文隔离
- ReceivePort和SendPort一起,是通信的唯一方式
- SendPort将消息发送到其他ReceivePort
demo
Isolate isolate;
void doIsolate() async {
var receive = ReceivePort();
isolate = await Isolate.spawn(echoResult, receive.sendPort);
receive.listen((message) {
print("message is $message");
});
}
/// 处理消息
void echoResult(SendPort port) {
final msg = "Hello world";
Timer.periodic(const Duration(seconds: 1), (timer) {
port.send(msg);
});
}
void kill() {
isolate.kill(priority: Isolate.immediate);
isolate = null;
}
除了这以外,还提供了一个更为简单的处理方法compute
。需要注意的是compute
方法运行中的方法必须是顶级方法或者静态方法。
testCompute() {
compute(execString, "hello").then((value) {
print("isolate compute $value "); ///isolate compute hello world
});
}
/// 此为顶级函数
Future execString(value) async {
await Future.delayed(Duration(milliseconds: 1000));
return value + " world";
}
Zone
表示Dart运行的环境,类似于一个沙盒。通过Zone我们还可以监听到全局范围内捕获到的异常
runZoned(() {
runApp(FlutterApp());
}, onError: (Objects obj, StackTrace stack) {
print(obj);
print(stack);
});
异步
- async/await
- Stream
扩展方法
和swift一样,可以对原有类进行扩展
demo
extension ExtendsFun on String {
int parseToInt() {
return int.tryParse(this);
}
}
main() {
String num = "4";
print( num.parseToInt()); // 4
}
常用控件
Flutter
中的Widget
可以分为两类,StatelessWidget
、StatefulWidget
。分表表示无状态和有状态的Widget
。
两者都是通过widget.build
方法构建UI
,不同之处StatefulWidget
可以进行刷新操作,生命周期也略有不同。
具体的类型控件自行查阅相关文档。
列举一些常用的Widget
控件 | 描述 |
---|---|
Container | 只有一个子Widget、默认充满,是一个集合了很多属性的容器视图,包含了:padding、margin、color、width、height、decoration等 |
Padding | 只有一个子Widget,只包含Padding的设置。多用于控制边距 |
Center | 只有一个子Widget,被其包起来的Widget会居中显示 |
Stack | 有多个子Widget,是一个列表,列表末尾的child会显示在最顶层 |
Column | 有多个子Widget,是一个列表,默认是从屏幕上至下,垂直排列 |
Row | 有多个子Widget,是一个列表,默认是从屏幕左至右,水平排列 |
Expanded | 只有一个子Widget,在Column和Row中撑满余下空间,如果要均分,可以设置其的flex属性 |
ListView | 和Column类似,区别之处就是可以超出屏幕范围,加载也会根据屏幕显示区域进行处理 |
UI更新
在实际开发中我们推送尽可能的使用StatelessWidget
,但是由于它是无状态的,所以就针对他的刷新机制推出了很多实现方案:Redux
、provider
、bloc
、provide
。这里推荐使用官方推崇的Provider
。
StatefulWidget
的生命周期
路由跳转
使用路由跳转时候可以使用pushName或者push方法,两个都可以进行导航操作;如果使用pushName,在必须在根App处进行定义,使用Push则没有这方面的要求
demo
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
routes: {
"weather": (_) => WeatherPage(),
}
);
}
}
// pushName
Navigator.pushName(context, 'weather');
// push
Navigator.push(context, MaterialPageRoute(build: (context) => WeatherPage()));