项目入口 lib/main.dart,文件入口为 main 函数
非静态语言,需要编译
项目结构
| drat | JS | -- |
|---|---|---|
| pubspec.yaml | package.json | |
| android | 打包安卓辅助 | |
| ios | 打包 IOS 辅助 | |
| web | chrome 调试辅助 | |
| lib | src | |
| assets | assets | 需要在 pubspec.yaml 中配置 |
https://pub.dev/ -> https://www.npmjs.com/
flutter packages get -> npm i
定义变量
| drat | C# | -- |
|---|---|---|
var |
- | 根据内容推断类型 |
late |
- | 稍后赋值 |
const |
CONST | 常量。编译前就确定的值 |
final |
READONLY/protected | 赋值后不可变更 |
_xxx |
private |
对于const编译器会做一些优化
const arr1 = [1,2,3]
const arr2 = [1,2,3]
print(arr1 == arr2) // true,强类型语言不需要===
final arr1 = [1,2,3]
final arr2 = [1,2,3]
print(arr1 == arr2) // false
数据类型:Dart 是强数据类型
| drat 类型 | JS 类型 | -- |
|---|---|---|
| Numbers | number | -- |
| Strings | string | -- |
| Boolean | bool | -- |
| Lists | array | 要求类型一致 |
| Sets | Set | var names = <String>{ 'a', 'b' } |
| Maps | Map,用法偏向 Object | var names = Map<String, String>(); |
| Object | - | 所有类型父类型,类型后期可变,强类型中的异类 |
| dynamic | Object | Object 增强版,编译器允许使用尽可能多的属性和方法 |
语法
if/else/for/while/do while/break/continue/switch case与 JS 用法一样
assert(isErr == true)可以中断执行流程
| drat | TS | -- |
|---|---|---|
| '''xxx\nxxx''' | xxx\nxxx |
多行文本 |
| str ?? '请输入' | str ?? '请输入' | |
| str || '请输入' | ||
| xxx?.size | xxx?.size | |
| xxx?.name! | 忽略此可选属性的为空检查 | |
| this is SomeClass | window instanceof Window | |
| 10 ~/ 6 | Math.floor(10/6) | 整除 |
| x ??= val | x ??= val | 仅在 x 为空值时赋值 |
| .. | 级联操作 | |
typedef NewType = ... |
type NewType = ... |
dart 中更像是类型别名,并不能自定义 |
bool functionName(bool arg) {} |
functionName(string arg): string {} |
定义方法 |
bool isNull(int n) => n == 0 |
isNull: (number n): bool => n == 0 |
箭头函数 |
void fn(bool a, [bool b]) {...} |
fn(a: boolean, b?: boolean):void {...} |
|
void fn({bool? a, bool? b}) {...} |
fn({a?: boolean, b?: boolean}):void {...} |
命名参数 |
fn(a: true, b: false) |
fn({a: true, b: false}) |
使用命名参数 |
void fn({bool a = true, bool? b}) {...} |
dart 不带?需要添加默认值 |
|
void fn({required bool a, bool? b}) {...} |
fn({a: boolean, b?: boolean}):void {...} |
必填参数 |
SomeClass(...) |
new SomeClass(...) |
|
| -- | -- | |
throw FormatException('xxx') |
throw New Error('xxx') |
|
throw 'xxx' |
||
try () on Exception catch() {} catch() {} |
try () catch() {} |
第一个 catch 用来捕获异常详细信息,第二个 catch 是堆栈跟踪信息 |
try () on Exception catch() {} finally {} |
如果没有 catch 子句匹配异常,则异常在 finally 子句运行后抛出 | |
| console.log | 如果没有 catch 子句匹配异常,则异常在 finally 子句运行后抛出 |
级联操作
var paint = Paint()
?..color = Colors.black
..strokeCap = StrokeCap.round
..strokeWidth = 5.0;
// 等价于
var paint = Paint();
paint?.color = Colors.black;
paint.strokeCap = StrokeCap.round;
paint.strokeWidth = 5.0;
异步
| JS | Dart |
|---|---|
| new Promise() | ? |
| Promise.then | Future.then |
| Promise.catch | Future.catchError |
| Promise.catch | Future.onError |
| Promise.finally | Future.whenComplete |
| Promise.all | Future.wait |
| async/await | async/await |
| Generator | Stream |
// new Promise()
Future<dynamic> chooseSchool() {
final completer = Completer();
route.open(XxxPage(), back: (arg) {
completer.complete(arg);
});
return completer.future;
}
类 class
-
构造函数与继承
class Person { final double x; final double y; Person(this.x, this.y); // 简化赋值 static void staticFn() { print('in staticFn'); } // 静态方法 Person.fromJson() { print('默认构造函数的语法糖'); }// 命名构造,返回一个实例 // 默认构造函数的语法糖,用来处理参数? } class Employee extends Person { Employee(): super(2, 4) { /* 先执行super,再执行此处 */ }; Employee.fromJson(super.data) : super.fromJson() { print('in Employee'); } } void main() { var employee = Employee(); print(employee.x); } -
Mixin 无继承无构造函数
class A extends B with Mixin1 -
枚举类型是一种特殊的类
enum Color { red, green, blue } Color c = Color.red; List<Color> allColor = Color.values print(c.name) // red print(allColor) // [MyColor.red, MyColor.green, MyColor.blue]
抽象类 abstract
| C# | Dart |
|---|---|
| 不可实例化 | same |
| 可以有非抽象方法 | same |
| 可被派生 | 可被继承 |
| ---- 实现方法需要 override 修饰 | ---- 不用 overrdie |
| ---- 非抽象方法规则同继承 | ---- same |
| 不可被实现 | 可被实现 |
| ---- | ---- 重写所有方法(有点像接口) |
库导入
import 'dart:html'; // 内置库
import 'package:test/test.dart';// pub工具提供的第三方包
import 'main/main_view.dart'; // 项目内引用
void _startApp() {} // 仅在当前文件内部可见
静态资源
- …/my_icon.png
- …/2.0x/my_icon.png
- …/3.0x/my_icon.png
Widget build(BuildContext context) {
// 根据DPI自动配置图片
return AssetImage('assets/my_icon.png');
// 依赖包中的图片
return AssetImage('icons/heart.png', package: 'some_pkg')
}
布局
组件的大小和位置由父组件决定,子级上的属性只是期望大小,不是真实大小,父元素没说默认最大值,有孩子元素 fit-content
子级的设置的大小大于父级可能会不生效,请明确指定它的对齐方式
-
StatelessWidget没有状态的组件,里面只需要重构build方法 -
StatefulWidget需要重构createState方法,方法返回一个State组件,build方法交由State组件重构 -
State访问StatefulWidget内的属性使用widget.xxx -
State生命周期initStatedidChangeDependencies-
build每次setState被调用都会触发此方法(是否有防抖?) -
reassemble热重载(hot reload)时会被调用 -
didUpdateWidget重新构建时 ? -
deactivate当 State 对象从树中被移除时. 在一些场景下,Flutter 框架会将 State 对象重新插到树中,如包含此 State 对象的子树在树的一个位置移动到另一个位置时(可以通过 GlobalKey 来实现)。如果移除后没有重新插入到树中则紧接着会调用 dispose()方法。 -
dispose当 State 对象从树中被永久移除时
-
- Text、Row、Column
- Stack:允许子 widget 堆叠,子组件可以基于 Stack 来定位(是基于 Web 开发中的绝对定位 absolute 布局模型设计的)
- Container:可让您创建矩形视觉元素。
-
Scaffold 骨架组件,参数 appBar、body
-
Material 组件
-
Cupertino 组件
组件间状态传递
全局状态管理:EventBus,Provider、GetX、Redux(??)
路由
-
Navigator:入栈(push)将一个页面插入栈顶;出栈(pop)删除栈顶页面// 压栈处理 Navigator.push( context, // build 方法的参数 MaterialPageRoute(builder: (_) => SecondPage()), ) // 出栈 Navigator.pop(context); -
MaterialPageRoute:继承自 PageRoute 类,表示占有整个屏幕空间的一个模态路由页面,它还定义了路由构建及切换时过渡动画的相关接口及属性MaterialPageRoute({ WidgetBuilder builder, // 返回新路由的实例 RouteSettings settings, // 路由的配置信息,如路由名称、是否初始路由(首页) bool maintainState = true, // 原路由是否要保存在内存中 bool fullscreenDialog = false, // 是否全屏模态对话框 }) -
页面间传参
// 压栈处理 final res = Navigator.push( context, // build 方法的参数 MaterialPageRoute(builder: (_) => SecondPage(arg: true)), ); print("页面返回的值是:$res"); // SecondScreen class SecondPage extends StatelessWidget { SecondPage({Key key, @required this.arg}): super(key: key); final bool arg; // 接受上页传来的参数 @override Widget build(BuildContext context) { ... Navigator.pop(context, 'i am SecondPage') -
命名路由
MaterialApp( title: 'Flutter Demo', theme: ThemeData(primarySwatch: Colors.blue), //名为"/"的路由作为应用的home(首页) initialRoute:"/", //注册路由表 routes:{ "new_page":(context) => NewRoute(), "/":(context) => MyHomePage(title: '首页'), //注册首页路由 }, ); // 跳转 Navigator.pushNamed(context, "new_page"); Navigator.pushReplacementNamed(context, "new_page"); // 参数传递 Navigator.pushNamed(context, "new_page", arguments: "hi"); @override Widget build(BuildContext context) { var args = ModalRoute.of(context).settings.arguments; // "hi" -
路由守卫
MaterialApp( ... //省略无关代码 onGenerateRoute:(RouteSettings settings){ return MaterialPageRoute(builder: (context){ String routeName = settings.name; // 如果访问的路由页需要登录,但当前未登录,则直接返回登录页路由。 } ); } );
调试 - vscode
先选择调试目标: vscode 右下角 Flutter Device 选择使用哪种方式调试(chrome、安卓/IOS 模拟器、以 USB 连接的手机等)
1 快捷键 F5 开始调试
2 在入口文件的 main 方法上方有三个按钮
Run | Debug | Profile
void main() async {
print('执行到这里了')
断点使用debugger() | 行号左侧点击 添加,在 vscode 运行和调试面板可以查看所有断点。
热重载使用调试 toolbar 闪电按钮
检查节点使用调试 toolbar 右侧带 flutter icon 的放大镜按钮
请求功能 DIO
路由工具、状态管理 Getx、Provider
JSON 转 model.dar https://jsontodart.zariman.dev/









网友评论