一、基础概念,参考资料
flutter主要发展方向为移动端跨平台方案。flutter的实现语言是dart,native端可支持的语言是安卓侧java、kotlin,ios侧oc、swift。 参考官网: https://flutterchina.club/docs/ https://flutter.dev/docs
依赖仓库地址: https://pub.dev/ 这个地址有所有的dart依赖仓库,通知也托管所有的flutter公共依赖。
二、主要模块
- 基础语法
在flutter中一切都是widget,包括基础组件,布局组件,样式组件,全部都用widget定义,这个带来了一些问题,样式和ui混合到了一起,如果自己团队没有设定一些约束,设定一些公用style,工程上显得比较混乱。
Text("我是一个text", style:TextStyle(fontSize:12,color:Colors(0xff333333)));
Image(image: AssetImage("images/my_image.png", package: 'my_package_name'));
Image(image: NetworkImage("https://xxx.xxx.xxx.png"));
Botton(
onTap:()=>{//dosomething},
image:Image.asset("xxxx.png"),
title:Text("xxxx"),
);
Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children:[
Text(...),
Button(...),
Row(...),
],
padding:const EdgeInsets.fromLTRB(20, 30, 20, 20),
);
/// container
/// row
- 工程类型
使用指令flutter create -t,可以创造一个仓库模板,仓库有几种类型,参考flutter create -h的说明,列举为下
- app (default) Generate a Flutter application.
主工程 - module Generate a project to add a Flutter module to an existing Android or iOS application.
如果想把flutter代码加入已有的Android、iOS工程下,可以使用这个仓库模板 - puglin Generate a shareable Flutter project containing an API in Dart code with a platform-specific implementation for Android, for iOS code, or for both.
包含Android或者iOS实现的仓库 - package Generate a shareable Flutter project containing modular Dart code.
仅包含dart代码的仓库,这个仓库可以创建.android和.ios两个隐藏文件夹作为运行环境,进行测试 - skeleton Generate a List View / Detail View Flutter application that follows community best practices.
未使用过
- 状态管理
- StatelessWidget和StatefulWidget
不需要做变更的组件,使用StatelessWidget即可。 可能有状态变化的组件,使用StatefulWidget。
class VariedWidget extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return VariedState();
}
}
class VariedState extends State<VariedWidget> {
String _state = "before";
@override
Widget build(BuildContext context) {
return Column(
children: [
Text(_state),
TextButton(
onPressed: () => {
setState(() {
_state = "after";
})
},
child: Text('点击改变状态'))
],
);
}
}
- 共享状态管理Provider
- 状态管理框架介绍
Provider是官方解决多个组件共用状态的方案,了解它也可以帮助我们理解其它第三方的状态管理框架 上述两点一同参考我编写的文档 https://docs.qq.com/doc/DRUxseWhXQ2FZWHdi
- 路由管理
- navigator
官方基础方案,查看Navigator.dart了解更多细节。官网示例:
import 'package:flutter/material.dart';
// ...
void main() => runApp(const MyApp());
// ...
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Code Sample for Navigator',
// MaterialApp contains our top-level Navigator
initialRoute: '/',
routes: <String, WidgetBuilder>{
'/': (BuildContext context) => const HomePage(),
'/signup': (BuildContext context) => const SignUpPage(),
},
);
}
}
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return DefaultTextStyle(
style: Theme.of(context).textTheme.headline4!,
child: Container(
color: Colors.white,
alignment: Alignment.center,
child: const Text('Home Page'),
),
);
}
}
class CollectPersonalInfoPage extends StatelessWidget {
const CollectPersonalInfoPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return DefaultTextStyle(
style: Theme.of(context).textTheme.headline4!,
child: GestureDetector(
onTap: () {
// This moves from the personal info page to the credentials page,
// replacing this page with that one.
Navigator.of(context)
.pushReplacementNamed('signup/choose_credentials');
},
child: Container(
color: Colors.lightBlue,
alignment: Alignment.center,
child: const Text('Collect Personal Info Page'),
),
),
);
}
}
class ChooseCredentialsPage extends StatelessWidget {
const ChooseCredentialsPage({
Key? key,
required this.onSignupComplete,
}) : super(key: key);
final VoidCallback onSignupComplete;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onSignupComplete,
child: DefaultTextStyle(
style: Theme.of(context).textTheme.headline4!,
child: Container(
color: Colors.pinkAccent,
alignment: Alignment.center,
child: const Text('Choose Credentials Page'),
),
),
);
}
}
class SignUpPage extends StatelessWidget {
const SignUpPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
// SignUpPage builds its own Navigator which ends up being a nested
// Navigator in our app.
return Navigator(
initialRoute: 'signup/personal_info',
onGenerateRoute: (RouteSettings settings) {
WidgetBuilder builder;
switch (settings.name) {
case 'signup/personal_info':
// Assume CollectPersonalInfoPage collects personal info and then
// navigates to 'signup/choose_credentials'.
builder = (BuildContext context) => const CollectPersonalInfoPage();
break;
case 'signup/choose_credentials':
// Assume ChooseCredentialsPage collects new credentials and then
// invokes 'onSignupComplete()'.
builder = (BuildContext _) => ChooseCredentialsPage(
onSignupComplete: () {
// Referencing Navigator.of(context) from here refers to the
// top level Navigator because SignUpPage is above the
// nested Navigator that it created. Therefore, this pop()
// will pop the entire "sign up" journey and return to the
// "/" route, AKA HomePage.
Navigator.of(context).pop();
},
);
break;
default:
throw Exception('Invalid route: ${settings.name}');
}
return MaterialPageRoute<void>(builder: builder, settings: settings);
},
);
}
}
参考api:https://api.flutter.dev/flutter/widgets/Navigator-class.html,基本上大多数常用的路由需求都可以解决,不过有一个缺点就是每一次使用都需要传入context,部分框架可以解决这个问题。
- 路由框架介绍
GetX可以作为一个比较快速的路由封装工具,建议可以加上跳转native页面的封装。
- 网络请求
- 国际化、主题管理
- 基础用法
国际化:https://flutterchina.club/tutorials/internationalization/ 主题管理:使用Provider即可 - 使用框架GetX
GetX也具有国际化和主题管理能力。参考:https://github.com/jonataslaw/getx/blob/master/README.zh-cn.md
- 自定义组件
- 代码规范
- 命名规范
- 分包规范
- 引用规范
参考:https://github.com/alibaba/flutter-go/blob/master/Flutter_Go%20%E4%BB%A3%E7%A0%81%E5%BC%80%E5%8F%91%E8%A7%84%E8%8C%83.md https://dart.cn/guides/language/effective-dart/style
- 单元测试
- dart测试
- widget测试
- 集成测试
参考:https://flutterchina.club/testing/
- 构建打包
参考:https://flutterchina.club/android-release/
三、空安全介绍
dart空安全是一种约束,如果某个依赖不支持空安全,那么整个项目也无法使用空安全的形式构建。所以为了让项目可以使用空安全特性,就要求整个项目所有依赖,都遵循空安全约束。
四、dart带来的一些特点和约束
- 拓展方法
extension关键字可以给已有的类,添加新的方法 - 因为flutter为了减少构建包的体积,所以未直接建立依赖关系的类,都会在构建中剔除,而反射可以引用到所有的类,flutter做的取舍就是禁用了dart的mirror库。
- 类型推断的疑问
使用泛型时,如果某个参数要求使用指定的t extends xxx,那么直接传入xxx,似乎也会报错,很奇怪的特点 - 资源路径的管理
image加载资源图片时,最好不要用绝对路径,而是用package指定包名,然后使用相对路径。不然在不同的路径引用,会显示不出图片。
五、flutter开发带来的感受
因为热加载可以实时刷新页面显示,所以开发页面非常的快速。 但是不是所有代码的调整都支持热加载,比如嵌套根App widget类的变更(这点和rn一样),比如资源的变更。
flutter没法使用反射,所以解析json类,显得格外繁琐。一般都是利用插件或者工具,自动生成解析代码。
flutter和rn一样解决了跨平台的问题。写一遍业务,可以应用到两端,减少了开发时间和测试压力。
但是我觉得rn对比flutter是有优势的。 两个方案实现的原理不一样, RN是利用虚拟dom,映射成native组件页面来实现跨平台。 flutter是dart引擎下,自己渲染所有的页面实现跨平台。
-
rn对原生的兼容性更好,做native的自定义组件时非常有优势。可以完美兼容所有的native组件。 而flutter嵌入原生view,还存在很多bug,比如软键盘没法监控弹出等。 -
而且rn社区应该更加庞大,因为react只要是前端就很容易掌握书写。而flutter需要单独学习dart语法,虽然dart很简单,但是dart中也有很多反直觉的约束,比如泛型的问题。
如果让我自己写项目,快速开发可能会选择flutter,但是作为一个想要长期支持的项目,不想出问题的项目,我会选择rn。
|