Flutter

Dart基础

Dart变量声明-var

1
2
3
4
5
6
7
8
void main(List<String> args) {
var age = 20;
print(age);
age =21;
print(age);
var age1= "测试1";
print(age1);
}
  • 语法: var 变量名=值/表达式;
  • 注意:当声明的变量类型第一次以后不能再更改其类型,例如:上述代码中不能将age在下面赋值
    String类型的值

Dart常量声明-const

1
2
3
4
5
6
7
8
9
10
11
void main(List<String> args) {
const num=3.1415926;
print(num);
num=100;//错误写法1
const length = 2* num*10;
print(length);

//第二种
var num1=3.1415926;
const num2=num1; //错误写法2
}
  • 常量不能更改
  • 常量表达式里面的值不能允许有变量

Dart常量声明-final

1
2
3
4
5
void main(List<String> args) {
//获取当前时间
final time = DateTime.now();
print(time);
}
  • 用法与const一样的
  • final与const的区别是 final是在运行时不可修改,const是编译时确定不可以修改

Dart中的常用数据类型

基本数据类型我就不写了只写一些不太相同的地方,重点集中于动态数据类型

  1. String 属性名 = ‘文本内容$变量名’; 或String 变量名=’文本内容${变量名}’
  2. 数值类型: int,double
  3. 布尔类型: bool
  4. 列表类型: List
  5. 映射类型: Map

Dart中的列表类型-List

  • 场景:当一个变量需要存储多个值的时候,可以使用列表类型List
  • 需求:一个班级的学生用List存储,支持对学生的查找、新增、删除、循环
  • 语法:List 属性名 = [‘学生1’, ‘学生2’];
1
2
3
4
void main(List<String> args) {
List students = ["张三", "李四", "王五"];
print(students);
}

输出结果:

1
[张三, 李四, 王五]

Dart中的列表类型-List的常用操作方法

  • 在尾部添加-add(内容)
  • 在尾部添加一个列表-addAll(列表)
  • 删除满足内容的第一个-remove(内容)
  • 删除最后一个-removeLast()
  • 删除索引范围内数据-removeRange(start,end)

Dart中的列表类型-List的常用操作方法和属性

  • 循环-forEach((item) {});
  • 是否都满足条件-every((item) { return 布尔值 });
  • 筛选出满足条件的数据-where((item) { return 布尔值 });
  • 列表的长度(属性)-length
  • 最后一个元素(属性)-last
  • 第一个元素(属性)-first
  • 是否为空(属性)-isEmpty

Dart中的字典类型-Map

Dart中的字典类型-Map的常用操作方法

  • 循环-forEach
  • 在添加一个字典-addAll
  • 是否包含某个key-containsKey
  • 删除某个key-remove
  • 清空-clear
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void main(List<String> args) {
// 定义一个字典
Map<String, String> transMap = {"hello": "你好", "world": "世界"};

// 循环
transMap.forEach((key, value) {
print('$key,$value');
});
// 添加一个字典
transMap.addAll({"fine": "很好"});
// 是否包含某个key
transMap.containsKey("fine");
// 删除某个key
transMap.remove("fine");
// 清空字典
transMap.clear();
}

Dart中的动态类型-dynamic和var的区别

区别对比

  • dynamic: 运行时可自由改变类型,无编译检查,方法和属性直接调用
  • var: 根据初始值进行推断类型,确定类型后类型确定,有编译检查,仅限推断的属性和方法

代码示例

1
2
3
4
5
6
7
void main(List<String> args) {
// 自由设置类型
var text = 1;
text.toDouble();
dynamic text1 = 1;
text1.startsWith(""); // 虽然运行报错,但是绕过编译,不会提示
}

Dart的空安全机制

空安全特性

  • 可空类型: 使用 ? 标记变量可以为 null
  • 安全访问: 使用 ?. 操作符安全访问可能为 null 的对象的方法或属性
  • 非空断言: 使用 ! 操作符告诉编译器变量一定不为 null(需谨慎使用)
  • 空合并操作符: 使用 ?? 提供默认值

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
void main(List<String> args) {
String? userename = null;// ? 表示可空类型
userename?.startsWith("新");// 表示安全访问
// ?表示客观
// !表示主观判断,开发者认为userename一定不为null
userename!.startsWith("xin");

//空合并,左侧为null,则返回右侧默认值
String displayName = userename ?? "默认用户";
print(displayName);

}

Dart中的函数

  • 场景:当一个功能需要被重复使用的时候,可以使用函数
  • 需求:一个班级的学生用List存储,支持对学生的查找、新增、删除、循环
  • 语法:void 函数名(参数1,参数2){ 函数体 }
1
2
3
4
5
6
7
8
void main(List<String> args) {
// 定义一个函数,用于判断字符串是否以新开头
int add(int a,int b){
return a+b;
}
int result = add(1,2);//调用
print(result);
}

注意:返回值类型可省略,Dart会自动推断类型为dynamic

可选位置参数

特点:可选位置参数必须位于必传参数后面,采用中括号包裹

语法函数名(String a, [String? b...])

传递方式:按照顺序传递

适用场景:参数少且顺序固定时

1
2
3
4
5
6
7
8
9
10
11
void main(List<String> args) {

int add(int a,int b,[int? c]){
return a+b+(c??0);
}
int result = add(1,2);
print(result);
// 可选参数可以不传递
int result2 = add(1,2,3);
print(result2);
}

可选命名参数

特点:可选命名参数采用大括号包裹,可按任意顺序传递

语法函数名(String a, {String? b, int? c})

传递方式函数名(a: '值', b: '值')

适用场景:参数多且顺序不固定时

1
2
3
4
5
6
7
8
9
10
11
12
void main(List<String> args) {
// 定义一个函数,用于判断字符串是否以新开头
bool isNewName(String name, {bool? isNew}) {
return isNew == true && name.startsWith("新");
}
// 调用函数时,可以不传递isNew参数,默认值为false
bool result = isNewName("张三");
print(result);
// 调用函数时,可以传递isNew参数,值为true
bool result2 = isNewName("新张三", isNew: true);
print(result2);
}

匿名函数

特点:可以声明一个没有名称的函数赋值给变量,进行调用

语法Function 变量名 = () {};

注意:函数的类型使用Function来声明

箭头函数

特点:当函数体只有一行代码时,可以使用箭头函数编写

语法函数名() => 代码逻辑

注意:使用箭头函数可以省略return关键字

代码示例

1
2
3
4
5
6
main(List<String> args) {
// 箭头函数
int add(int a, int b) => a + b;
int result = add(1, 2);
print(result);
}

Dart中的类

类的定义

定义:Dart语言中,类(class)是面向对象编程的核心,类包含属性和方法来定义对象的行为和状态

需求:定义一个Person类,属性包括姓名、年龄、性别,包括学习的方法

定义类语法class Person{属性方法}

实例化对象Person 变量 = Person();

属性和方法变量.属性/方法()

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Person {
// 属性
String name;
int age;
String gender;

// 构造函数
Person(this.name, this.age, this.gender);

// 方法
void study() {
print('$name正在学习');
}
}

void main(List<String> args) {
// 实例化对象
Person person = Person('张三', 18, '男');

// 访问属性
print(person.name);
print(person.age);
print(person.gender);

// 调用方法
person.study();
}

构造函数

Dart中类的构造函数-默认构造函数

定义:实例化对象的时候,使用构造函数直接给对象中的属性赋值

常见分类:默认构造函数、命名构造函数、构造函数的语法糖

定义语法

1
2
3
4
5
class 类名 {
类名(可选命名参数) {
// 构造函数体
}
}

实例化语法

1
Person p = new Person(属性: 值);

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Person {
String? name = ""; // 姓名
int? age = 0; // 年龄
String? sex = "男"; // 性别

//默认构造函数
Person({String? name, int? age, String? sex}) {
this.name = name;
this.age = age;
this.sex = sex;
}

void study() {
print("$name在学习");
}
}

Dart中类的构造函数-命名构造函数

定义:构造函数可以采用命名的方式,返回一个实例化对象

定义语法

1
2
3
4
5
class 类名 {
类名.构造函数名(可选命名参数) {
// 构造函数体
}
}

实例化语法

1
Person p = Person.构造函数名(属性: 值);

注意:默认构造函数和命名构造函数可同时存在

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class Person {
String? name = ""; // 姓名
int? age = 0; // 年龄
String? sex = "男"; // 性别

//默认构造函数
Person({String? name, int? age, String? sex}) {
this.name = name;
this.age = age;
this.sex = sex;
}

// 命名构造函数
Person.withName(String name) {
this.name = name;
}

void study() {
print("$name在学习");
}
}

void main(List<String> args) {
// 使用默认构造函数
Person p1 = Person(name: "张三", age: 18, sex: "男");

// 使用命名构造函数
Person p2 = Person.withName("李四");

p1.study();
p2.study();
}

#### Dart中类的构造函数-构造函数语法糖

**定义**:同名构造函数和命名构造函数都支持简写写法

**语法**:
```dart
class 类名 {
类名({ this.属性1, this.属性2 });

类名.命名函数({ this.属性1, this.属性2 });
}

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Person {
String? name;
int? age;
String? sex;

// 命名构造函数
// Person(this.name, this.age, this.sex); // 简写
Person.createPerson({this.name, this.age, this.sex}); // 命名函数简写

void study() {
print('$name在学习');
}
}

void main(List<String> args) {
Person p = Person.createPerson(name: '张三');
p.study();
Person pp = Person.createPerson(name: '张三');
pp.study();
}

私有属性和公有属性

公有属性:提供自身或者其他外部文件和类使用的属性和方法

私有属性:仅供自身使用的属性和方法,其他外部文件和类无法访问

语法:私有属性以下划线开头,如_name,其余均为公有属性

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class Person {
// 公有属性
String? name;
int? age;

// 私有属性
String? _sex;

Person({this.name, this.age, String? sex}) {
_sex = sex;
}

// 公有方法
void study() {
print('$name在学习');
}

// 私有方法
void _privateMethod() {
print('这是一个私有方法');
}

// 通过公有方法访问私有属性和方法
void showSex() {
print('性别: $_sex');
_privateMethod();
}
}

void main(List<String> args) {
Person p = Person(name: '张三', age: 18, sex: '男');

// 访问公有属性
print(p.name);
print(p.age);

// 访问公有方法
p.study();
p.showSex();

// 无法直接访问私有属性和方法
// print(p._sex); // 错误
// p._privateMethod(); // 错误
}

Dart中类的继承

继承的定义

定义:继承是拥有父类的属性和方法

特点:Dart属于单继承,一个类只能拥有一个直接父类,子类拥有父类所有的属性和方法

语法class 类名 extends 父类

重写:子类可通过@override注解重写父类方法,扩展其行为

注意:子类不会继承父类构造函数,子类必须通过super关键字调用父类构造函数确保父类正确初始化

super语法子类构造函数(可选命名参数): super({参数})

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void main(List<String> args) {
Child c = Child(name: '张三', age: 18);
c.sayHello();
}
class Parent{
String? name;
int? age;

Parent({this.age,this.name});

void sayHello(){
print('Hello, my name is $name, I am $age years old.'+'I am a parent.');
}
}
class Child extends Parent{
//子类的构造函数
Child({String? name,int? age}):super(name: name,age: age);

@override
void sayHello(){
super.sayHello();
print('Hello, my name is $name, I am $age years old.'+'I am a child.');
}
}

Dart中类的多态

多态的定义

定义:Dart中的多态是指同一操作作用于不同的对象,可以产生不同的执行效果

场景:微信和支付宝都遵循同样支付接口,但实现逻辑不同,即同一个支付操作拥有不同的支付效果

实现方式

  1. 继承和方法重写
  2. 抽象类和接口

多态示例-继承和方法重写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class BasePay {
void Pay() {
print("基础支付功能");
}
}

class WXPay extends BasePay {
@override
void Pay() {
// TODO: implement Pay
super.Pay();
print("微信支付");
}
}

class AliPay extends BasePay {
@override
void Pay() {
// TODO: implement Pay
super.Pay();
print("支付宝支付");
}
}

void main(List<String> args) {
BasePay P = WXPay();
P.Pay();
BasePay pay = new AliPay();
pay.Pay();
}

多态示例-抽象类和接口实现

方式:使用abstract关键字声明一个抽象类(没有实现体)

方式:使用implements关键字继承并实现抽象类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 定义抽象类
abstract class PayBase {
void pay();
}

// 微信支付类
class WxPay implements PayBase {
@override
void pay() {
print("微信支付");
}
}

// 支付宝支付类
class AliPay implements PayBase {
@override
void pay() {
print("支付宝支付");
}
}

// 调用支付
void main(List<String> args) {
PayBase p = WxPay();
p.pay();
}

Dart中类的混入

混入的定义

定义:Dart允许在不使用传统继承的情况下,向类中添加新的功能

方式

  1. 使用mixin关键字定义一个对象
  2. 使用with关键字将定义的对象混入到当前对象

特点:一个类支持with多个mixin,调用优先级遵循”后来居上”原则,即后混入的会覆盖先混入的同名方法

需求:让一个学生类和一个老师类都拥有唱歌的方法

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// 定义混入
mixin Singing {
void sing() {
print('正在唱歌');
}
}

// 学生类
class Student {
String? name;

Student(this.name);
}

// 老师类
class Teacher {
String? name;

Teacher(this.name);
}

// 混入后的学生类
class SingingStudent extends Student with Singing {
SingingStudent(String name) : super(name);
}

// 混入后的老师类
class SingingTeacher extends Teacher with Singing {
SingingTeacher(String name) : super(name);
}

void main(List<String> args) {
SingingStudent student = SingingStudent('张三');
student.sing();

SingingTeacher teacher = SingingTeacher('李四');
teacher.sing();
}

Dart中异步编程-事件循环

事件循环的介绍

介绍:Dart是单线程语言,即同时只能做一件事,遇到耗时任务就会造成程序阻塞,此时需要异步编程

定义:Dart采用单线程+事件循环的机制完成耗时任务的处理

事件循环的执行顺序

  1. 执行同步代码
  2. 执行微任务队列
  3. 执行事件队列
  4. 结束

微任务队列Future.microtask()

事件队列FutureFuture.delayed()、I/O操作(文件、网络)等

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void main(List<String> args) {
Future future = Future((){
return "Hello Future";
});
future.then((value){
//第一个任务
Future(() => "task1");
}).then((onValue){
//第二个任务
Future(() => "task2");
}).then((onValue){
//第三个任务
Future(() => "task3");
}).catchError((onError){
print("出现错误");
});

}

Dart中异步编程-Future-async/await

async/await的介绍

介绍:除了通过then/catchError的方式,还可以通过async/await来实现异步编程

特点await总是等到后面的Future执行成功,才执行下方逻辑,async必须配套await出现

语法

1
2
3
4
5
6
7
8
函数名() async {
try {
await Future();
// Future执行成功才执行的逻辑
} catch(error) {
// 执行失败的逻辑
}
}

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void main(List<String> args) async {
print('开始执行');

// 使用async/await
String result = await fetchData();
print('获取到数据: $result');

print('执行完毕');
}

Future<String> fetchData() {
return Future.delayed(Duration(seconds: 2), () {
return '模拟网络请求获取的数据';
});
}