Flutter 从入门到实战(一):Dart 语言基础
面向刚接触 Flutter 的同学。内容以"能快速上手、适合发布博客"为目标,重新组织了章节结构与表达方式。
一、为什么要学 Flutter
Flutter 是 Google 开源的一套跨平台 UI 开发工具包,目标是使用一套代码,构建接近原生体验的多端应用。
它的价值主要体现在 3 个方面:
-
开发效率高
一套 Dart 代码可以同时面向 Android、iOS、Web、Windows,甚至更多平台。
-
性能与体验更均衡
Flutter 直接控制渲染层,在很多场景下能获得比较流畅的界面表现。
-
企业落地广
课程讲义中提到,Flutter 在跨平台方案中拥有很高的采用率,已经有大量实际应用落地。
如果你想做跨端应用,但又不想分别深入 Android 和 iOS 原生开发,Flutter 是一个很值得投入的方向。
二、这套课程在讲什么
这份讲义整体是一个渐进式学习路径,核心分为 3 个部分:
- Dart 语言基础
- Flutter 组件核心
- 综合案例实战
其中第一份讲义的重点,主要是帮助我们先把 Dart 打牢。原因很简单:Flutter 的开发语言就是 Dart,如果语言基础不稳,后面的组件、状态、网络请求、项目结构都会学得很吃力。
三、开始前需要准备什么
1. 安装 Dart SDK
Dart SDK 是 Dart 官方提供的工具包,负责代码编写、运行、调试和编译。
我们可以把它理解为:想学 Flutter,先把 Dart 的运行环境准备好。
2. 准备编辑器
讲义中推荐了支持 AI 能力的编辑器 Trae,并提到两种常见工作方式:
-
Tab补全模式编写代码时,AI 根据上下文自动补全。
-
Builder协作模式直接用自然语言描述需求,让 AI 协助生成或修改代码。
不管你最终使用哪款编辑器,建议至少具备以下能力:
- Dart 语法高亮
- 自动补全
- 报错提示
- 运行与调试支持
3. Dart 初学者注意事项
刚开始写 Dart 时,先记住这几个基本规则:
- 文件后缀是
.dart - 程序入口通常是
main() - 大多数语句需要以分号结尾
- 大括号后的语法规则要和其他现代语言区分清楚
一个最简单的 Dart 程序如下:
dart
void main() {
print('Hello Dart');
}
四、变量与常量:先搞清楚"值会不会变"
在 Dart 中,最先要理解的是变量和常量的区别。
1. var:用于声明变量
当一个值后续还会变化时,使用 var。
dart
void main() {
var age = 20;
age = 21;
print(age);
}
特点:
- Dart 会根据初始值自动推断类型
- 类型一旦推断完成,就不能随意改成别的类型
dart
void main() {
var name = 'Tom';
// name = 18; // 会报错,因为 name 已经被推断为 String
}
2. const:编译时常量
如果一个值从定义开始就不会变化,并且在编译阶段就能确定,使用 const。
dart
void main() {
const pi = 3.1415926;
print(pi);
}
适用场景:
- 固定配置
- 数学常量
- 永远不会变化的字面量
3. final:运行时常量
如果一个值只会赋值一次,但这个值要等到运行时才能确定,就使用 final。
dart
void main() {
final now = DateTime.now();
print(now);
}
4. var、const、final 怎么选
可以直接记住这套判断逻辑:
- 值会变:用
var - 值不变,且编译时确定:用
const - 值不变,但运行时才确定:用
final
五、Dart 常用数据类型
讲义重点介绍了 6 类常用数据类型:
StringintdoublenumboolListMapdynamic
1. 字符串 String
字符串用于描述文本内容。
dart
void main() {
String title = 'Flutter 入门';
print(title);
}
模板字符串
模板字符串是 Dart 中非常常用的能力:
dart
void main() {
String mealTime = '早上 8 点';
String text = '我要在 $mealTime 的时候吃早饭';
print(text);
}
如果是表达式,可以写成 ${表达式}:
dart
void main() {
int a = 10;
int b = 20;
print('总和是 ${a + b}');
}
2. 数字类型 int、double、num
它们的区别可以简单理解为:
int:整数double:浮点数num:既可以表示整数,也可以表示小数
dart
void main() {
int age = 18;
double score = 98.5;
num price = 100;
price = 99.9;
}
需要注意的是,不同数字类型之间并不是所有情况都能直接互相赋值,这一点在实际编码中要格外小心。
3. 布尔类型 bool
布尔类型只有两个值:true 和 false。
dart
void main() {
bool finishedHomework = true;
print(finishedHomework);
}
4. 列表类型 List
当一个变量要保存多个值时,通常使用 List。
dart
void main() {
List<String> students = ['小明', '小红', '小刚'];
print(students);
}
常用操作包括:
add():尾部添加元素addAll():追加一组元素remove():删除指定元素removeLast():删除最后一个元素forEach():遍历where():筛选every():判断是否全部满足条件
示例:
dart
void main() {
List<int> scores = [88, 92, 75, 99];
scores.add(100);
var goodScores = scores.where((item) => item >= 90);
print(goodScores.toList());
}
5. 字典类型 Map
Map 用于保存键值对数据。
dart
void main() {
Map<String, String> dict = {
'apple': '苹果',
'banana': '香蕉',
};
print(dict['apple']);
}
常见操作有:
forEach()addAll()containsKey()remove()clear()
6. 动态类型 dynamic
dynamic 表示动态类型,变量在运行时可以自由改变类型。
dart
void main() {
dynamic value = 'hello';
value = 123;
value = true;
print(value);
}
但要注意,dynamic 会绕过很多编译期检查。也就是说,它虽然灵活,但会降低代码的安全性和可维护性。
dynamic 和 var 的区别
这是初学者特别容易混淆的一点:
var是类型推断,不是动态类型dynamic才是真正意义上的"运行时再决定类型"
简化理解:
dart
void main() {
var a = 'hello';
// a = 123; // 不允许
dynamic b = 'hello';
b = 123; // 允许
}
实际开发里,能不用 dynamic 就尽量不用。
六、空安全:Dart 非常重要的一道保护
空安全是 Dart 很重要的特性,它的核心目标是把很多空指针问题提前到编译阶段暴露出来,而不是等程序跑起来再崩。
1. 可空与不可空
默认情况下,类型是不可为空的:
dart
String name = 'Flutter';
如果允许为空,要加 ?:
dart
String? name;
2. 常见空安全操作
常用写法包括:
?:声明可空类型?.:空值安全调用!:非空断言??:空值兜底??=:当变量为空时再赋值
示例:
dart
void main() {
String? nickname;
print(nickname?.length);
print(nickname ?? '默认昵称');
nickname ??= '游客';
print(nickname);
}
! 虽然可以强制告诉编译器"这里一定不为空",但使用时一定要谨慎,否则还是可能在运行时报错。
七、运算符:写逻辑的基础
讲义中把常见运算符分成 4 类:
- 算术运算符
- 赋值运算符
- 比较运算符
- 逻辑运算符
1. 算术运算符
常见有:
+-*/~/:整除%:取余
dart
void main() {
print(7 / 2); // 3.5
print(7 ~/ 2); // 3
print(7 % 2); // 1
}
2. 赋值运算符
常见有:
=+=-=*=/=%=
3. 比较运算符
比较运算结果一定是布尔值:
==!=><>=<=
4. 逻辑运算符
用于处理布尔表达式:
&&:并且||:或者!:取反
dart
void main() {
bool isAdult = true;
bool hasTicket = false;
print(isAdult && hasTicket);
}
八、流程控制:让程序能"判断"和"循环"
1. if 分支
if 用于条件判断,是最基础的控制结构。
dart
void main() {
int score = 85;
if (score >= 90) {
print('优秀');
} else if (score >= 60) {
print('及格');
} else {
print('不及格');
}
}
2. 三元运算符
适合简化双分支逻辑:
dart
void main() {
int age = 20;
String result = age >= 18 ? '成年人' : '未成年';
print(result);
}
3. switch / case
当条件很多,而且本质上是在做"相等判断"时,switch 会更清晰。
dart
void main() {
String level = 'vip';
switch (level) {
case 'vip':
print('高级会员');
break;
case 'normal':
print('普通会员');
break;
default:
print('游客');
}
}
4. while 循环
while 适合"只要条件满足就一直执行"的场景。
dart
void main() {
int i = 0;
while (i < 3) {
print(i);
i++;
}
}
5. for 循环
for 是最常见的循环结构之一,也很适合遍历集合。
dart
void main() {
List<String> names = ['A', 'B', 'C'];
for (int i = 0; i < names.length; i++) {
print(names[i]);
}
}
九、函数:把重复逻辑封装起来
函数是 Dart 代码组织和复用的核心能力。
1. 基本定义
dart
int add(int a, int b) {
return a + b;
}
2. 返回值
函数可以有返回值,也可以没有返回值:
dart
int sum(int a, int b) {
return a + b;
}
void logMessage() {
print('hello');
}
3. 必传参数
dart
String getUserName(String name) {
return name;
}
4. 可选位置参数
使用中括号包裹:
dart
String joinName(String first, [String? second]) {
return '$first ${second ?? ''}';
}
适合参数顺序明确、可省略的场景。
5. 可选命名参数
使用大括号包裹,并通过"参数名: 值"的方式传参:
dart
String createUser(String name, {int? age, String? city}) {
return '$name - ${age ?? 0} - ${city ?? '未知'}';
}
void main() {
print(createUser('Tom', age: 20, city: 'Shanghai'));
}
这种写法在 Flutter 中非常常见,因为可读性更好。
6. 匿名函数
匿名函数没有名字,常用于回调场景。
dart
void main() {
List<int> list = [1, 2, 3];
list.forEach((item) {
print(item);
});
}
7. 箭头函数
当函数体只有一行时,可以用箭头函数简化:
dart
int square(int x) => x * x;
十、类与面向对象:Flutter 开发绕不开的基础
Flutter 中大量代码都建立在类和对象之上,所以 Dart 的面向对象能力必须理解。
1. 定义类
dart
class Person {
String name;
int age;
Person(this.name, this.age);
void study() {
print('$name 正在学习');
}
}
2. 构造函数
讲义中提到 3 类常见构造方式:
- 默认构造函数
- 命名构造函数
- 构造函数语法糖
默认构造函数
dart
class Person {
String name;
int age;
Person(this.name, this.age);
}
命名构造函数
dart
class Person {
String name;
int age;
Person(this.name, this.age);
Person.guest()
: name = '游客',
age = 0;
}
3. 公有与私有成员
Dart 中以下划线开头的属性或方法,通常表示私有成员。
dart
class User {
String name = 'Tom';
String _token = 'abc123';
}
4. 继承
Dart 是单继承语言,一个类只能有一个直接父类。
dart
class Animal {
void run() {
print('动物在跑');
}
}
class Dog extends Animal {
@override
void run() {
print('小狗在跑');
}
}
5. 多态
多态的核心是:同样的调用,面对不同对象时,会有不同实现。
这通常通过继承和方法重写来体现。
6. 抽象类与接口实现
当你只想约束规范,而不直接提供完整实现时,可以使用抽象类:
dart
abstract class Pay {
void pay();
}
class WechatPay implements Pay {
@override
void pay() {
print('微信支付');
}
}
7. 混入 mixin
如果你想在不走传统继承链的情况下,为类扩展能力,可以使用 mixin。
dart
mixin Runner {
void run() {
print('running');
}
}
class Person with Runner {}
8. 泛型
泛型的价值是:既限制类型,又保留复用能力。
dart
class Box<T> {
T value;
Box(this.value);
}
void main() {
Box<String> box = Box<String>('hello');
print(box.value);
}
十一、异步编程:Dart 处理耗时任务的方式
异步编程是 Flutter 开发里的高频内容,因为网络请求、文件读写、数据库访问都离不开它。
1. 事件循环
讲义中强调了一个关键点:Dart 是单线程模型,但它通过事件循环机制来协调同步任务和异步任务。
可以简单理解为:
- 先执行主线程中的同步代码
- 遇到耗时任务时,不阻塞主流程
- 等异步结果准备好后,再回到事件循环中处理
2. Future
Future 表示一个未来才会拿到结果的异步操作。
dart
Future<String> getData() async {
return '请求成功';
}
它通常有几种状态:
- 等待中
- 成功完成
- 失败完成
3. 链式调用
可以使用 then() 和 catchError() 处理结果:
dart
Future<String> getData() async {
return 'ok';
}
void main() {
getData()
.then((value) {
print(value);
})
.catchError((e) {
print(e);
});
}
4. async / await
相比链式调用,async / await 更接近同步代码的书写方式,可读性通常更好。
dart
Future<String> getData() async {
return 'ok';
}
void main() async {
try {
String result = await getData();
print(result);
} catch (e) {
print(e);
}
}
对于 Flutter 初学者来说,建议优先把 Future 和 async / await 熟练掌握,因为后续请求接口、初始化数据、处理用户动作时都会频繁用到。
十二、学完这一讲,应该掌握什么
如果这份 Dart 基础讲义已经吸收得比较扎实,你至少应该具备下面这些能力:
- 能看懂并编写简单的 Dart 程序
- 能区分
var、const、final - 能熟练使用
String、List、Map等常见类型 - 理解空安全的基本规则与常见操作符
- 能使用分支、循环、函数组织基础逻辑
- 能理解类、构造函数、继承、多态、泛型等面向对象概念
- 能读懂并书写基本异步代码
十三、从 Dart 过渡到 Flutter,下一步学什么
Dart 基础打好之后,接下来进入 Flutter 会顺畅很多。下一阶段建议重点关注这些内容:
- Flutter 环境配置
- 工程目录结构
main.dart入口文件- StatelessWidget 与 StatefulWidget
- 常见基础组件
- 页面布局与滚动容器
- 生命周期与状态更新
也就是说,Dart 解决的是"语言怎么写"的问题,而 Flutter 解决的是"界面怎么搭、交互怎么跑、项目怎么组织"的问题。
结语
很多人一学 Flutter 就急着写页面、搭项目、调接口,结果一遇到状态更新、空安全报错、回调函数、异步逻辑就开始混乱。根本原因往往不是 Flutter 太难,而是 Dart 基础不够稳。
真正高效的学习顺序应该是:
- 先把 Dart 语言基础打牢
- 再进入 Flutter 组件与项目开发
- 最后通过综合案例把知识串起来
如果你准备系统学习 Flutter,这一讲最值得反复练习的内容有 3 块:
- 变量与数据类型
- 函数与类
- 空安全与异步编程
把这 3 块吃透,后面学习 Flutter 会轻松很多。