1.初始化项目

  • 项目目录 ``` flutter_app andriod # 安卓目录 build # 构建目录 ios # ios目录 lib # 开发目录(相当于src目录) main.dart # 入口文件(相当于index.js) test # 测试目录 .gitignore # git忽略文件 pubspec.lock # 项目依赖锁定信息(相当于package-lock.json) pubspec.yaml # 项目依赖配置(相当于package.json)
  1. - 入口文件与入口方法
  2. - Material DesignGoogle推出的前端UI解决方案)
  3. - 官网:https://www.material.io
  4. - 中文网:[https://material-io.cn](https://material-io.cn)
  5. - Flutter中一切内容都是组件(Widget
  6. - 无状态组件(StatelessWidget
  7. - 有状态组件(StatefulWidget
  8. <a name="YjQtJ"></a>
  9. ### 2.App结构
  10. - MaterialApp
  11. - title(任务管理器中的标题)
  12. - home(主内容)
  13. - debugShowCheckedModeBanner(是否显示左上角调试标记)
  14. - Scaffold
  15. - appBar(应用头部)
  16. - body(应用主题)
  17. - floatingActionButton(浮动按钮)
  18. - drawer(左侧抽屉菜单)
  19. - endDrawer(右侧抽屉菜单)
  20. ![](https://cdn.nlark.com/yuque/0/2022/jpeg/21507977/1642544101034-2ed02850-76b0-43de-9b2d-96eecef50279.jpeg)<br />![](https://cdn.nlark.com/yuque/0/2022/jpeg/21505355/1644825698719-86884d3f-80ab-48ef-9151-89163907546a.jpeg)
  21. <a name="eowsw"></a>
  22. ### 3.基础组件-常用
  23. **Text**
  24. - Text
  25. - TextDirection(文本方向)
  26. - TextStyle(文本样式)
  27. - Colors(文本颜色)
  28. - FontWeight(字体粗细)
  29. - FontStyle(字体样式)
  30. - TextAlign(文本对齐)
  31. - TextOverflow(文本溢出)
  32. - maxLines(指定显示的行数)
  33. - RichTextTextSpan(组合使用,给一段文本声明不同的样式)
  34. **设置自定义字体**
  35. - 下载并导入字体
  36. - [https://fonts.google.com]()
  37. - 加压压缩包,将字体文件复制到flutter项目中
  38. - pubspec.yaml中声明字体
  39. ```yaml
  40. fonts:
  41. - family: SourceSansPro
  42. fonts:
  43. - asset: fonts/Source_Sans_Pro/SourceSansPro-Black.ttf
  44. - asset: fonts/Source_Sans_Pro/SourceSansPro-BlackItalic.ttf
  45. weight: 300
  46. style: italic
  • 使用
    • 为整个应用设置默认自定义字体
    • 为某个组件设置自定义字体

Icon

Color

  • Color(自定义颜色)
    • Flutter中通过ARGB来声明颜色
    • const Color(0xFF42A5F5); // 16进制的ARGB=透明度+六位十六进制颜色
    • const Color.fromARGB(0xFF, 0x42, 0xA5, 0xF5);
    • const Color.fromARGB(255, 66, 165, 245);
    • const Color.fromRGBO(66, 165, 245, 1.0); // Opacity
  • Colors(英文字母声明的颜色)
    • Colors.red

布局-Container

  • child(声明子组件)
  • padding(margin)
    • EdgeInsets(all()、fromLTRB()、only())
  • decoration
    • BoxDecoration(边框、圆角、渐变、阴影、背景色、背景图片)
  • alignment
    • Alignment(内容对齐)
  • transform
    • Matrix4(平移-translate、旋转-rotate、缩放-scale、斜切-skew)

布局-线性布局

  • Column
    • Column中主轴方向是垂直方向
    • mainAxisAlignment: MainAxisAlignment主轴对齐方式
    • crossAxisAlignment: CrossAxisAlignment交叉轴对齐方式
    • children: 内容
  • Row
    • Row中的主轴方向是水平方向(其它属性与Column一致)

布局-弹性布局

  • Flex
    • direction(声明主轴方向)
    • mainAxisAlignment(声明主轴对齐方式)
    • textDirection(声明水平方向的排列顺序)
    • crossAxisAlignment(声明交叉轴对齐方式)
    • verticalDirection(声明垂直方向的排列顺序)
    • children(声明子组件)
  • Expanded(可伸缩组件 )
    • flex(声明弹性布局所占比例)
    • child(声明子组件)

布局-流式布局

  • Wrap(解决内容溢出问题)
    • spacing(主轴方向子组件的间距)
    • alignment(主轴方向的对齐方式)
    • runSpacing(纵轴方向子组件的间距)
    • runAlignment(纵轴方向的对齐方式)
  • Chip(标签)
  • CircleAvatar(圆形头像)

布局-层叠布局

  • Stack(层叠组件-类似CSS中的z-index)
    • alignment(声明未定位的子组件对齐方式)
    • textDirection(声明未定位子组件的排列顺序)
  • Positioned(绝对定位组件)
    • child(声明子组件)
    • left、top、right、bottom
    • width、height
  • NetworkImage(网络图片组件)
    • NetworkImage(‘图片地址’)

布局-Card

  • Card(卡片)
    • child子组件
    • color 背景色
    • shadowColor 阴影色
    • elevation 阴影高度
    • shape 边框样式
    • margin 外边框
  • ListTile(列表瓦片)
      • leading(头部组件)
    • title(标题)
    • subtitle(子标题)

按钮

  • Flutter1.2之前(不用了)
    • FlatButton(扁平按钮)
      • 主题 ButtonTheme
    • RaisedButton(凸起按钮)
      • 主题 ButtonTheme
    • OutlineButton(轮廓按钮)
      • 主题 ButtonTheme
  • Flutter1.22之后
    • TextButton(文本按钮-用来替换FlatButton)
      • 主题 TextButtonTheme
    • ElevatedButton(凸起按钮-用来替换RaisedButton)
      • 主题 OutlinedButtonTheme
    • OutlinedButton(轮廓按钮-用来替换OutlineButton)
      • 主题 ElevatedButtonTheme
  • 为什么会新增按钮?
    • 以前的按钮调整未统一的外观比较麻烦,经常自定义大量按钮样式
    • 新按钮将外观属性集合为一个ButtonStyle,非常方便统一控制
  • 图标按钮
    • IconButton
    • TextButton.Icon()
    • ElevatedButton.icon()
    • OutlinedButton.Icon()
  • ButtonBar(按钮组)
  • FloatingActionButton(浮动按钮)
  • BackButton(回退按钮)
  • CloseButton(关闭按钮)

图片

  • Image.asset(加载本地图片)
    • 在Flutter项目下,创建图片存储目录
    • 在pubspec.yaml中的flutter部分添加图片配置
    • 在代码中加载图片
  • Image.network(加载网络图片)
    • 保证网络畅通
    • 设置网络访问权限
    • 允许http协议访问

image.png
列表-SingleChildScrollView

  • SingleChildScrollView(类似Android中的ScrollView)
    • child(子组件)
    • padding(内边距)
    • scrollDirection(滚动方向:Axis.horizontal | Axis.vertical)
    • reverse(初始滚动位置,false头部,true尾部)
    • phusics
      • ClampingScrollPhysics:Andriod下的微光效果
      • BouncingScrollPhysics:IOS下弹性效果

列表-ListView

  • ListView
    • 加载列表的组件(加载所有的Widgets,适用Widget较少的场景)
    • ListTile(leading、title、subtitle、trailing、selected)
  • ListView.builder
    • 按需加载Widget,性能比默认构造函数高,适用Widget较多的场景
  • ListView.separated
    • 比ListeView.builder多了分隔器

列表-GridView

  • GridView(网格布局)
    • children(子组件)
    • scrollDirection(滚动方向)
    • gridDelegate
      • SliverGridDelegateWithFixedCrossAxisCount(指定列数-子组件宽度自适应)
        • crossAxisCount: 2, // 指定列数
        • mainAxisSpacing: 20, // 主轴方向间距
        • crossAxisSpacing: 10, // 交叉轴间距
        • childAspectRatio: 1.5, // 子组件宽高比
      • SliverGridDelegateWithMaxCrossAxisExtent(指定子组件宽度-列数自适应)
        • maxCrossAxisExtent: 200, // 指定宽度
    • GridView.count(列数固定)
    • GridView.extend(子组件宽度固定)
    • GridView.builder(动态网格布局)
  • ScrollPhysics physics(确定可滚动控件的物理特性)
    • BouncingScrollPhysics(允许超出边界-反弹效果)
    • ClampingScrollPhysics(防止超出边界-夹住效果)
    • AlwaysScrollableScrollPhysics(始终响应滚动)
    • NeverScrollableScrollPhysics(不响应滚动)

其它-Cupertino

第三方组件
dio

Flutter_swiper

  • Flutter中最好的轮播组件,适配Andriod和ios
  • 使用步骤
    • 在pubsepc.yaml中添加flutter_swiper依赖
    • 安装依赖(pub get | flutter packages get | VS Code中保存配置,自动下载)
    • 引入import ‘package:flutter_swiper/flutter_swiper.dart’;
    • 使用https://pub.dev/packages/flutter_swiper/install
  • 使用问题,flutter2.0版本以后限制了safety模式,包不支持就会报错
    • image.png
  • 解决方案,在vscode中增加不校验safety的配置

    • image.png
      1. "args": [
      2. "--no-sound-null-safety"
      3. ]
      shared_preferences
  • shared_preferences是一个本地数据缓存库(类似AsyncStorage)

  • 使用步骤
    • 在pubsepc.yaml中添加shared_preferences依赖
    • 安装依赖(pub get | flutter packages get | VS Code中保存配置,自动下载)
    • 引入import ‘package:shared_preferences/shared_preferences.dart’;
    • 使用SharedPreferences prefs = await SharedPreferences.getInstance();
  • 操作

      • setString(key, value)
      • remove(key) | clear()
      • 更改就是重新设置数据
      • setString(key, value)
      • getString(key)

        4.状态管理

        StatefulWidget
  • Flutter中的组件,按状态划分:

    • StatelessWidget(无状态组件)
    • StatefulWidget(状态组件)
  • 按状态作用域划分
    • 组件内私有状态(StatefulWidget)
    • 跨组件状态共享(InhreitedWidget、Provider)
    • 全局状态(Redux | fish-redux、Mobx)
  • 状态组件的组成
    • StatefulWidget(组件本身不可变-@immutable)
    • State(将变化的状态放到State中维护)

DataTable

  • DataTable是Flutter中的表格
    • columns(声明表头列表)
      • DataColumn(表头单元格)
    • rows(声明数据列表)
      • DataRow(一行数据)
        • DataCell(数据单元格)
    • 其它属性

生命周期

  • initState()组件对象插入到元素树中
  • didChangeDependencies()当前状态对象依赖发生变化时
  • build() 组件渲染
  • setState()组件内部状态变更
  • didUpdateWidget()组件配置更新
  • deactivate()组件对象在元素树中暂时移除
  • dispose()组件对象在元素中永远移除

Flutter-基础 - 图4
provider

Flutter-基础 - 图5
Provider-使用

  • 安装Provider(第三方库)
  • 创建数据模型(T extends ChangeNotifier)
  • 创建Provider(注册数据模型)
    • Provider() // 不会被要求随着变动而变动
    • ChangeNotifierProvider() // 随着默写数据的改变而被通知更新
  • 获取数据模型并更新UI
    • 通过上下文(BuildContext)
    • 通过静态方法(Provider.of(context))

MultiProvider

  1. // CurrentIndexProvider
  2. class CurrentIndexProvider with ChangeNotifier {
  3. int _currentIndex = 0;
  4. int get currentIndex => _currentIndex;
  5. changeIndex(int index) {
  6. _currentIndex = index;
  7. notifyListeners();
  8. }
  9. }
  10. // main.dart
  11. runApp(
  12. MultiProvider(
  13. providers: [
  14. ChangeNotifierProvider.value(value: CurrentIndexProvider()),
  15. // 还可以写若干个provider
  16. ],
  17. child: const MyApp()
  18. )
  19. );
  20. // 使用
  21. class Index extends StatefulWidget {
  22. const Index({Key? key}) : super(key: key);
  23. @override
  24. _IndexState createState() => _IndexState();
  25. }
  26. class _IndexState extends State<Index> {
  27. final List<BottomNavigationBarItem> bottomNavItems = [
  28. BottomNavigationBarItem(
  29. backgroundColor: Colors.blue, icon: Icon(Icons.home), label: '首页'),
  30. BottomNavigationBarItem(
  31. backgroundColor: Colors.blue,
  32. icon: Icon(Icons.pause_presentation_rounded),
  33. label: '学习'),
  34. BottomNavigationBarItem(
  35. backgroundColor: Colors.blue, icon: Icon(Icons.person), label: '我的'),
  36. ];
  37. final pages = [
  38. {"title": Text("拉钩首页"), "page": Home()},
  39. {"title": Text("学习中心"), "page": Study()},
  40. {"title": Text("个人中心"), "page": Mine()}
  41. ];
  42. // int currentIndex = 0;
  43. @override
  44. Widget build(BuildContext context) {
  45. // int currentIndex = Provider.of<CurrentIndexProvider>(context).currentIndex;
  46. // 语法糖
  47. int currentIndex = context.watch<CurrentIndexProvider>().currentIndex;
  48. return Scaffold(
  49. appBar: AppBar(
  50. title: pages[currentIndex]["title"],
  51. centerTitle: true,
  52. elevation: 0,
  53. ),
  54. bottomNavigationBar: BottomNavigationBar(
  55. items: bottomNavItems,
  56. currentIndex: currentIndex,
  57. selectedItemColor: Colors.red,
  58. type: BottomNavigationBarType.fixed,
  59. onTap: (index) {
  60. // Provider.of<CurrentIndexProvider>(context, listen: false)
  61. // .changeIndex(index);
  62. // 语法糖
  63. context.read<CurrentIndexProvider>().changeIndex(index);
  64. }));
  65. }
  66. }

监听调用

  • Provider.of(context) | context.watch(context)
  • 只能在[StatelessWidget.build]和[State.build]中使用
  • 监听值发生变化时,会重建组件

非监听调用

  • Provider.of(context, listen: false) | context.read(context)
  • 不能在[StatelessWidget.build]或[State.build]中使用;
  • 监听值发生变化时,不会重建组件

    5.路由与导航

    路由简介

  • Route

    • 一个路由是一个屏幕或页面的抽象
  • Navigator
    • 管理路由的组件,Navigator可以通过路由入栈和出栈来实现页面之间的跳转
    • 常用属性:
      • initialRoute:初始路由,即默认页面
      • onGenerateRoute:动态路由(根据规则,匹配动态路由)
      • onUnknownRoute:未知路由,也就是404
      • routes:路由集合

匿名路由

  • Navigator
    • push(跳转指定组件)

Navigator.push(context, MaterialPageRoute(builder:(context) => 组件名称))

  • pop(回退)

Navigator.pop(context)
命名路由

  • 声明路由
    • routes路由表(map类型)
    • initialRoute(初始路由)
    • onUnknownRoute(未知路由-404)
  • 跳转到命名路由
    • Navigator.pushNamed(context, ‘路由名称’);

动态路由

  • 动态路由是指通过onGenerateRoute属性指定的路由

路由传参

  • 匿名路由
    • 路由中声明参数
      • Navigator.push
    • 组件中接收参数 ```dart Navigator.push(context, MaterialPageRoute(builder: (context) { return BlogDetail( id: blogItem[‘id’] ) }) )

class BlogDetail extends StatefulWidget { BlogDetail({Key key, required this.id}): super(key: key); final int id; }

  1. - 命名路由
  2. - 路由中声明参数
  3. - Navigator.pushNamed(context, routename, {arguments})
  4. - 组件中接收参数
  5. - ModalRoute.of(context).settings.arguments
  6. ```dart
  7. Navigator.pushNamed(
  8. context,
  9. '/homePage',
  10. arguments: {'title': '传参'}
  11. )
  12. class HomePage extends StatelessWidget {
  13. final Map arguments = ModalRoute.of(context).settings.arguments;
  14. String title = arguments['title'];
  15. }

Drawer导航

  • Scaffold
    • drawer(左侧抽屉菜单)
    • endDrawer(右侧抽屉菜单)
  • UserAccountsDrawerHeader
    • 抽屉菜单头部组件
  • AboutListTile
    • 关于弹窗

BottomNavigationBar导航

  • items
    • 包含导航(BottomNavigationBar)的列表
  • currentIndex
    • 当前导航索引
  • type
    • 导航类型(BottomNavigationBarType)
  • onTap()
    • 导航的点击事件(一般会更新导航索引)

Tab导航

  • DefaultTabController(整个Tab导航的容器)
    • length(声明导航的数量)
    • child(指定子组件)
  • TabBar(导航菜单)
    • tabs(导航菜单数组)
  • TabBarView(导航页面)

    • children(多个导航页面内容)

      6.Form

      Switch
  • Switch

    • value(开关的值,一般与状态字段绑定)
    • onChanged(开关状态变更时调用)
    • activeColor(开关开启时圆圈的颜色)
    • activeTrackColor(开关开启时的轨道颜色)
    • inactiveThumbColor(开关关闭时的圆圈颜色)
    • inactiveTrackColor(开关关闭时的轨道颜色)
  • CupertinoSwitch(IOS风格的开关)
    • import ‘package:flutter/cupertino.dart’;

Checkbox

  • Checkbox
    • value(复选框的值)
    • onChanged(复选框状态更改时调用)
    • activeColor(选中时,复选框背景的颜色)
    • checkColor(选中时,复选框对号的颜色)
  • CheckboxListTile
    • title
    • subtitle

Radio

  • Radio(单选框)
    • value(开关值,一般与状态字段绑定)
    • onChanged(开关状态变更时调用)
    • gropValue(选择组的值)
  • RadioListTile(单选列表)
    • value(开关的值,一般与状态字段绑定)
    • onChanged(开关状态变更时调用)
    • gropValue(选择组的值)

TextField

  • autofocus(是否获取焦点)
  • keyboardType(键盘类型)
  • obscureText(设置为密码框)
  • decoration(样式装饰)
  • onChanged(内容更改自动调用-onChanged)
  • labelText(标题)
  • hintText(提示文字-placeholder)
  • maxLines(显示行数-文本域)

Calendar

  • CalendarDatePicker(日历选择器)
    • initalCalendarMode
      • DatePickerMode.day
      • DatePickerMode.year
  • showDatePicker
    • initialDatePickerMode(year | day)
    • initialEntryMode(calendar | input)
  • showTimePicker(时间选择器)

Form

  • 使用步骤
    • 创建表单Form,并以GlobalKey作为唯一性标识
    • 添加带验证逻辑的TextFormField到Form中
    • 创建按钮以验证和提交表单
  • Form(表单容器)
    • 创建表单唯一键:final GlobalKey _formKey = GlobalKey();
    • 验证表单:_formKey.currentState.validate()
    • 提交表单:_formKey.currentState.save()
    • 重置表单:_formKey.currentState.reset()
    • child(子组件)
  • TextFormField(输入框)

    • 与TextField的区别:必须在Form内使用&带有验证器
    • validator(验证器)
    • obscureText(密码框)
    • onSaved
      • 设定表单字段的值
      • 在表单save()方法之后执行

        7.其它

        动画
  • Why

    • UI界面设计合理的动画,可以让用户感觉更加流畅、直观,可以极大提高和改善用户体验。
  • What(实现原理)
    • 动画就是动起来的画面
    • 视觉暂留:画面经视觉神经 传入大脑后,不会立即消失(会存留一段时间)
    • 帧(Frame):单个的画面,在学术上叫帧。
    • 每秒钟展示的帧数简称fps

动画分类

  • 补间(Tween)动画
    • 在补间动画中我们定义开始点和结束点、时间线以及定义转换时间和速度曲线。然后我们由系统计算,从开始点运动到结束点。从而形成动画效果
    • 列如:透明度从0到1,颜色值从0到255
  • 拟物动画
    • 拟物动画就是对真实世界的行为进行建模,使动画效果类似于现实中的物理效果。
    • 列如:弹簧、阻尼、重力、抛物线等。

Animation

  • Animation,是flutter动画库中的一个核心类。它包含动画的值和状态两个属性,定义了动画的一系列监听函数。
    • 监听值:
      • addListener
      • removeListener
    • 监听状态:
      • addStatusListener
      • removeStatusListener

动画状态

  • Animation.dismissed
    • 动画的初始状态
  • Animation.completed
    • 动画的结束状态
  • AnimationStatus.forward
    • 动画处在从开始到结束的运行状态
  • AnimationStatus.reverse
    • 动画处在从结束到开始的运行状态

AnimationController

  • AnimationController(动画控制器)
    • 在指定时间内,将组件属性值由初始值演变到终止值。从而形成动画效果
  • AnimationController参数
    • duration(动画的执行时间)
    • reverseDuration(动画的反向执行时间)
    • lowerBound = 0.0(动画的最小值)
    • upperBound = 1.0 (动画最大值)
    • value(动画初始值,默认是lowerBound)
    • vsync(TickerProvider类型的对象,用来创建Ticker对象)
  • 当创建一个AnimationController时,需要传递一个vsync参数

    • vsync的作用:防止屏幕外动画消耗不必要的资源(列如切后台)
    • 通过将SingleTickerProviderStateMixin添加到类定义中,可以将stateful对象作为vsync的值。 ```dart class AnimationDemo extends StatefulWidget { const AnimationDemo({Key key}) : super(key: key);

    @override _AnimationDemoState createState() => _AnimationDemoState(); }

class _AnimationDemoState extends State with SingleTickerProviderStateMixin {

AnimationController controller; Animation animation;

@override void initState() { // TODO: implement initState super.initState();

  1. // 1.创建 AnimationController
  2. controller =
  3. AnimationController(duration: Duration(milliseconds: 400), vsync: this);
  4. // 2.1 声明动画曲线
  5. animation = CurvedAnimation(parent: controller, curve: Curves.bounceIn);
  6. // 2.2 设置动画值的范围
  7. animation = Tween(begin: 50.0, end: 400.0).animate(controller);
  8. // 3. 监听动画
  9. animation.addListener(() {
  10. print(animation.value);
  11. setState(() {});
  12. });
  13. // 4. 执行动画
  14. controller.forward();

}

@override Widget build(BuildContext context) { return Center( Icon(Icons.favorite, color: Colors.red, size: animation.value), ); } }

  1. - AnimationController具有控制动画的方法:
  2. - .forward()可以正向执行动画
  3. - .reverse()可以反向执行动画
  4. - .dispose()用来释放动画资源(在不使用时需要调用该方法,否则会造成资源泄露)
  5. - .stop()用来停止动画运行
  6. **Tween**
  7. - 简介
  8. - AnimationController动画生成值得默认区间是0.01.0,如果希望使用不同得区间,或不同得数据类型,需要使用Tween(补间动画)
  9. - Tween得唯一职责就是定义从输入范围到输出范围得映射。
  10. - 列如:颜色区间是0255
  11. - Tween
  12. - Tween<double>(begin; 起始值, end: 结束值);
  13. - ColorTween(begin: Colors.white, end: Colors.black);
  14. **CurvedAnimation**
  15. - 简介
  16. - 动画执行得速度有多种(匀速、先快后慢或先慢后快)这里的速度称为动画曲线
  17. - CurvedAnimation的目的是为了AnimationController添加动画曲线
  18. - 组件
  19. - CurvedAnimation(parent: controller, curve: Curves.easeIn)
  20. - parent(动画控制器对象)
  21. - curve(正向执行的动画曲线)
  22. - reverseCurve(反向执行的动画曲线)
  23. - Curves
  24. - 动画曲线:[https://api.flutter.dev/flutter/animation/Curves-class.html](https://api.flutter.dev/flutter/animation/Curves-class.html)
  25. **步骤**
  26. - 创建动画控制器
  27. - controller = AnimationController(duration, vsync多个动画的)
  28. - 创建动画
  29. - 动画曲线(CurvedAnimation
  30. - 补间动画(Tween
  31. - 监听动画
  32. - addListener() 监听动画生成值
  33. - addEventListener() 监听动画状态
  34. - 执行动画
  35. - controller.forward() 正向执行
  36. - controller.reverse() 方向执行
  37. **交织动画**
  38. - what
  39. - 交织动画是由多个单一动画叠加而成的复杂动画
  40. - 列如:组件变化可能涉及高度、宽度、颜色、透明度、位置等等。
  41. - 需要给每个动画设置间隔时间
  42. - Transform(对组件进行矩阵变化)
  43. - 平移:Transform.translate()
  44. - 旋转:Transform.rotate()
  45. - 缩放:Transform.scale()
  46. **Hero动画**
  47. - Hero动画用来实现跨页面的动画效果
  48. - 在不同页面中,声明一个共享组件(Hero
  49. - 由于共享组件在不同页面中的位置、外观等不同,路由切换时,形成动画效果
  50. - 如何实现
  51. - 在页面A中定义起始Hero组件(source hero),声明tag
  52. - 在页面B中定义目标Hero组件(destination hero),绑定相同的tag
  53. - 页面跳转时,通过Navigator,传递tag
  54. - Hero组件
  55. - tag(路由切换时,共享组件的标记)
  56. - child(声明子组件)
  57. **多语言(国际化)**
  58. - 国际化(internationalization简称i18n
  59. - 终端(手机)系统语言切换时,Flutter应用的跟随切换
  60. - 内容
  61. - 组件(Widget)国际化
  62. - 列如:日历,弹窗等常用组件的国际化
  63. - 文本国际化(包括文本顺序)
  64. - 自定义文本国际化
  65. **组件国际化**
  66. - pubspec.yaml中引入flutter_localizations
  67. - 安装包:flutter pub getVS Code中自动保存安装)
  68. - 设置MaterialApp
  69. - import 'package:flutter_localizations/flutter_localizations.dart';
  70. - localizationsDelegates(指定哪些组件需要国际化)
  71. ```dart
  72. localizationsDelegates: [
  73. // 本地化代理
  74. CustomLocalizations.delegate,
  75. GlobalMaterialLocalizations.delegate,
  76. GlobalCupertinoLocalizations.delegate,
  77. GlobalWidgetsLocalizations.delegate,
  78. ],
  • supportedLocales(指定需要支持哪些语言)
    1. supportedLocales: [
    2. const Locale('en', 'US'),
    3. const Locale('zh', 'CN')
    4. ]
  • 查看组件效果
    • 在模拟器上,将语言设置为中文

文本多语言

  • 创建本地化类
    • CustomLocalizations
  • 创建本地化类的代理
    • CustomLocalizationsDelegate extends LocalizationsDelegate
      • isSupported(当前本地化,是否在有效的语言范围内)
      • shouldReload(本地化重新构建时,是否调用load方法,加载本地化资源)
      • load(语言发生变更时,加载对应的本地化资源)
  • 使用本地化类
    • CustomLocalizations.delegate ```dart import ‘package:flutter/foundation.dart’; import ‘package:flutter/material.dart’;

class CustomLocalizations { final Locale locale;

CustomLocalizations(this.locale);

static Map> _localizedValues = { “en”: { “title”: “Home”, “greet”: “Hello”, }, “zh”: { “title”: “首页”, “greet”: “你好”, }, };

String t(String key) { _localizedValues[‘zh’][‘title’] return _localizedValues[locale.languageCode][key]; }

static CustomLocalizations of(BuildContext context) { return Localizations.of(context, CustomLocalizations); }

static CustomLocalizationsDelegate delegate = CustomLocalizationsDelegate(); }

class CustomLocalizationsDelegate extends LocalizationsDelegate { @override bool isSupported(Locale locale) { return [“en”, “zh”].contains(locale.languageCode); }

@override Future load(Locale locale) async { return SynchronousFuture(CustomLocalizations(locale)); }

@override bool shouldReload(covariant LocalizationsDelegate old) { return false; } }

  1. **加载语言包**
  2. - 检测当前语言
  3. - localeResolutionCallback
  4. - locale.languageCode(语言代码,列如:enzh
  5. - locale.countryCode(国家代码,列如:USCN
  6. ```dart
  7. localeResolutionCallback: (locale, supportedLocales) {
  8. print('deviceLocale: $locale');
  9. print('languageCode: ${locale.languageCode}');
  10. print('countryCode: ${locale.countryCode}');
  11. for (var supportedLocale in supportedLocales) {
  12. if (supportedLocale.languageCode == locale.languageCode &&
  13. supportedLocale.countryCode == locale.countryCode) {
  14. return supportedLocale;
  15. }
  16. }
  17. return supportedLocales.first;
  18. },
  • 设置语言包
    • 创建语言文件
    • 在pubsub.yaml中配置语言资源
  • 异步加载语言包
    • 在CustomLocalizations中,添加loadJSON()方法
    • 在CustomLocalizationsDelegate中,调用CustomLocalizations的loadJSON()方法

多主题

  • 主题(UI风格、样式、皮肤)
    • 主题风格可通过theme来定义,从而实现整个App风格的统一
    • 一旦设置了主题,那么应用程序中的某些Widget,就会直接使用主题的样式
  • 组件
    • ThemeData
      • Brightness(Brightness.light | Brightness.dart)
      • primaryColor | accentColor
      • buttonTheme | cardTheme | iconTheme | textTheme
    • Theme(声明局部主题)
      • Theme.of(context)获取上下文中的主题信息

适配终端

  • 声明不同的主题
    • CustomTheme
  • 使用主题
    • import ‘CustomTheme.dart’;
    • theme: CustomTheme.lightTheme,
    • darkTheme: CustomTheme.darkTheme,
    • theme: ThemeData.light(),
    • darkTheme: ThemeData.dark()
  • 查看效果

    • 模拟器中切换主题,Flutter应用中查看效果

      8.企业级路由解决方案Fluro路由

  • 安装(https://pub.dev/packages/fluro)

  • 声明路由处理器 ```dart import ‘package:flutter/material.dart’; import ‘package:fluro/fluro.dart’; import ‘../pages/index.dart’; import ‘../pages/user/Login.dart’; import ‘../pages/notfound/NotFound.dart’;

// 首页 var indexHandler = Handler(handlerFunc: (context, params) { return const Index(); });

// 登录页 var loginHandler = Handler(handlerFunc: (context, params) { return const Login(); });

// 404 var notFoundHandler = Handler(handlerFunc: (context, params) { return const NotFound(); });

  1. - 声明路由
  2. ```dart
  3. // Global.dart
  4. import 'package:flutter/material.dart';
  5. import 'package:fluro/fluro.dart';
  6. class G {
  7. // 路由
  8. static FluroRouter router = FluroRouter();
  9. }
  10. // main.dart
  11. import 'package:flutter/material.dart';
  12. import 'package:fluro/fluro.dart';
  13. import 'pages/index.dart';
  14. import 'routes/Routes.dart';
  15. import 'utils/Global.dart';
  16. void main() {
  17. // 初始化路由
  18. FluroRouter router = new FluroRouter();
  19. Routes.configureRoutes(router);
  20. // 初始化路由放到全局组件中
  21. G.router = router;
  22. runApp(const MyApp());
  23. }
  24. class MyApp extends StatelessWidget {
  25. const MyApp({Key? key}) : super(key: key);
  26. // This widget is the root of your application.
  27. @override
  28. Widget build(BuildContext context) {
  29. return MaterialApp(
  30. title: 'Flutter Demo',
  31. // home: Index(),
  32. // 动态路由
  33. onGenerateRoute: G.router.generator,
  34. initialRoute: '/');
  35. }
  36. }
  • 使用路由
    1. ElevatedButton(
    2. onPressed: () {
    3. G.router.navigateTo(context, '/login');
    4. },
    5. child: Text('跳转到登录页')
    6. )

    9.Dio接口插件

    ```dart // initDio.dart import ‘package:dio/dio.dart’;

Dio initDio() { // 声明dio的配置向 BaseOptions _baseOptions = new BaseOptions( baseUrl: “http://poetry.apiopen.top“, connectTimeout: 5000); // 初始化dio Dio dio = Dio(_baseOptions);

// 添加拦截器 dio.interceptors.add(InterceptorsWrapper( // 请求拦截 onRequest: (RequestOptions options) { print(‘请求之前进行拦截’); }, // 响应拦截 onResponse: (Response options) { print(‘响应之前拦截’); }, // 报错拦截 onError: (DioError options) { print(‘报错之前拦截’); }, ));

return dio; }

// API.dart

```