项目入口 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
生命周期initState
didChangeDependencies
-
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/
网友评论