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)
- 入口文件与入口方法
- Material Design(Google推出的前端UI解决方案)
- 官网:https://www.material.io
- 中文网:[https://material-io.cn](https://material-io.cn)
- Flutter中一切内容都是组件(Widget)
- 无状态组件(StatelessWidget)
- 有状态组件(StatefulWidget)
<a name="YjQtJ"></a>
### 2.App结构
- MaterialApp
- title(任务管理器中的标题)
- home(主内容)
- debugShowCheckedModeBanner(是否显示左上角调试标记)
- Scaffold
- appBar(应用头部)
- body(应用主题)
- floatingActionButton(浮动按钮)
- drawer(左侧抽屉菜单)
- endDrawer(右侧抽屉菜单)
![](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)
<a name="eowsw"></a>
### 3.基础组件-常用
**Text**
- Text
- TextDirection(文本方向)
- TextStyle(文本样式)
- Colors(文本颜色)
- FontWeight(字体粗细)
- FontStyle(字体样式)
- TextAlign(文本对齐)
- TextOverflow(文本溢出)
- maxLines(指定显示的行数)
- RichText和TextSpan(组合使用,给一段文本声明不同的样式)
**设置自定义字体**
- 下载并导入字体
- [https://fonts.google.com]()
- 加压压缩包,将字体文件复制到flutter项目中
- 在pubspec.yaml中声明字体
```yaml
fonts:
- family: SourceSansPro
fonts:
- asset: fonts/Source_Sans_Pro/SourceSansPro-Black.ttf
- asset: fonts/Source_Sans_Pro/SourceSansPro-BlackItalic.ttf
weight: 300
style: italic
- 使用
- 为整个应用设置默认自定义字体
- 为某个组件设置自定义字体
Icon
- Icon
- Flutter中的图标库
- Icon(Icons.具体名称0)
- 在线预览
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
- FlatButton(扁平按钮)
- Flutter1.22之后
- TextButton(文本按钮-用来替换FlatButton)
- 主题 TextButtonTheme
- ElevatedButton(凸起按钮-用来替换RaisedButton)
- 主题 OutlinedButtonTheme
- OutlinedButton(轮廓按钮-用来替换OutlineButton)
- 主题 ElevatedButtonTheme
- TextButton(文本按钮-用来替换FlatButton)
- 为什么会新增按钮?
- 以前的按钮调整未统一的外观比较麻烦,经常自定义大量按钮样式
- 新按钮将外观属性集合为一个ButtonStyle,非常方便统一控制
- 图标按钮
- IconButton
- TextButton.Icon()
- ElevatedButton.icon()
- OutlinedButton.Icon()
- ButtonBar(按钮组)
- FloatingActionButton(浮动按钮)
- BackButton(回退按钮)
- CloseButton(关闭按钮)
图片
- Image.asset(加载本地图片)
- 在Flutter项目下,创建图片存储目录
- 在pubspec.yaml中的flutter部分添加图片配置
- 在代码中加载图片
- Image.network(加载网络图片)
- 保证网络畅通
- 设置网络访问权限
- 允许http协议访问
列表-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, // 指定宽度
- SliverGridDelegateWithFixedCrossAxisCount(指定列数-子组件宽度自适应)
- GridView.count(列数固定)
- GridView.extend(子组件宽度固定)
- GridView.builder(动态网格布局)
- ScrollPhysics physics(确定可滚动控件的物理特性)
- BouncingScrollPhysics(允许超出边界-反弹效果)
- ClampingScrollPhysics(防止超出边界-夹住效果)
- AlwaysScrollableScrollPhysics(始终响应滚动)
- NeverScrollableScrollPhysics(不响应滚动)
其它-Cupertino
- Material
- 安卓风格的组件
- import ‘package:flutter/material.dart’
- Cupertino
- ios风格的组件
- import ‘package:flutter/cupertino.dart’
- https://flutter.dev/docs/development/ui/widgets/cupertino
- SafeArea
- SafeArea可以有效解决异形屏问题
第三方组件
dio
- dio是一个强大的Dart Http请求库(类似axios)
- 使用步骤
- 在pubsepc.yaml中添加dio依赖
- 安装依赖(pub get | flutter packages get | VS Code中保存配置,自动下载)
- 引入import ‘package:dio/dio.dart’;
- 使用:https://pub.dev/documentation/dio/latest
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模式,包不支持就会报错
解决方案,在vscode中增加不校验safety的配置
shared_preferences"args": [
"--no-sound-null-safety"
]
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();
操作
Flutter中的组件,按状态划分:
- StatelessWidget(无状态组件)
- StatefulWidget(状态组件)
- 按状态作用域划分
- 组件内私有状态(StatefulWidget)
- 跨组件状态共享(InhreitedWidget、Provider)
- 全局状态(Redux | fish-redux、Mobx)
- 状态组件的组成
- StatefulWidget(组件本身不可变-@immutable)
- State(将变化的状态放到State中维护)
DataTable
- DataTable是Flutter中的表格
- columns(声明表头列表)
- DataColumn(表头单元格)
- rows(声明数据列表)
- DataRow(一行数据)
- DataCell(数据单元格)
- DataRow(一行数据)
- 其它属性
- columns(声明表头列表)
生命周期
- initState()组件对象插入到元素树中
- didChangeDependencies()当前状态对象依赖发生变化时
- build() 组件渲染
- setState()组件内部状态变更
- didUpdateWidget()组件配置更新
- deactivate()组件对象在元素树中暂时移除
- dispose()组件对象在元素中永远移除
provider
- Provider是对InheritedWidget的封装
- 优势
- 简化资源的分配与配置
- 懒加载
Provider-使用
- 安装Provider(第三方库)
- 创建数据模型(T extends ChangeNotifier)
- 创建Provider(注册数据模型)
- Provider() // 不会被要求随着变动而变动
- ChangeNotifierProvider() // 随着默写数据的改变而被通知更新
- 获取数据模型并更新UI
- 通过上下文(BuildContext)
- 通过静态方法(Provider.of
(context))
MultiProvider
// CurrentIndexProvider
class CurrentIndexProvider with ChangeNotifier {
int _currentIndex = 0;
int get currentIndex => _currentIndex;
changeIndex(int index) {
_currentIndex = index;
notifyListeners();
}
}
// main.dart
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider.value(value: CurrentIndexProvider()),
// 还可以写若干个provider
],
child: const MyApp()
)
);
// 使用
class Index extends StatefulWidget {
const Index({Key? key}) : super(key: key);
@override
_IndexState createState() => _IndexState();
}
class _IndexState extends State<Index> {
final List<BottomNavigationBarItem> bottomNavItems = [
BottomNavigationBarItem(
backgroundColor: Colors.blue, icon: Icon(Icons.home), label: '首页'),
BottomNavigationBarItem(
backgroundColor: Colors.blue,
icon: Icon(Icons.pause_presentation_rounded),
label: '学习'),
BottomNavigationBarItem(
backgroundColor: Colors.blue, icon: Icon(Icons.person), label: '我的'),
];
final pages = [
{"title": Text("拉钩首页"), "page": Home()},
{"title": Text("学习中心"), "page": Study()},
{"title": Text("个人中心"), "page": Mine()}
];
// int currentIndex = 0;
@override
Widget build(BuildContext context) {
// int currentIndex = Provider.of<CurrentIndexProvider>(context).currentIndex;
// 语法糖
int currentIndex = context.watch<CurrentIndexProvider>().currentIndex;
return Scaffold(
appBar: AppBar(
title: pages[currentIndex]["title"],
centerTitle: true,
elevation: 0,
),
bottomNavigationBar: BottomNavigationBar(
items: bottomNavItems,
currentIndex: currentIndex,
selectedItemColor: Colors.red,
type: BottomNavigationBarType.fixed,
onTap: (index) {
// Provider.of<CurrentIndexProvider>(context, listen: false)
// .changeIndex(index);
// 语法糖
context.read<CurrentIndexProvider>().changeIndex(index);
}));
}
}
监听调用
- 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; }
- 命名路由
- 路由中声明参数
- Navigator.pushNamed(context, routename, {arguments})
- 组件中接收参数
- ModalRoute.of(context).settings.arguments
```dart
Navigator.pushNamed(
context,
'/homePage',
arguments: {'title': '传参'}
)
class HomePage extends StatelessWidget {
final Map arguments = ModalRoute.of(context).settings.arguments;
String title = arguments['title'];
}
Drawer导航
- Scaffold
- drawer(左侧抽屉菜单)
- endDrawer(右侧抽屉菜单)
- UserAccountsDrawerHeader
- 抽屉菜单头部组件
- AboutListTile
- 关于弹窗
BottomNavigationBar导航
- items
- 包含导航(BottomNavigationBar)的列表
- currentIndex
- 当前导航索引
- type
- 导航类型(BottomNavigationBarType)
- onTap()
- 导航的点击事件(一般会更新导航索引)
Tab导航
- DefaultTabController(整个Tab导航的容器)
- length(声明导航的数量)
- child(指定子组件)
- TabBar(导航菜单)
- tabs(导航菜单数组)
TabBarView(导航页面)
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
- initalCalendarMode
- 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(子组件)
- 创建表单唯一键:final GlobalKey
TextFormField(输入框)
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
AnimationController controller; Animation animation;
@override void initState() { // TODO: implement initState super.initState();
// 1.创建 AnimationController
controller =
AnimationController(duration: Duration(milliseconds: 400), vsync: this);
// 2.1 声明动画曲线
animation = CurvedAnimation(parent: controller, curve: Curves.bounceIn);
// 2.2 设置动画值的范围
animation = Tween(begin: 50.0, end: 400.0).animate(controller);
// 3. 监听动画
animation.addListener(() {
print(animation.value);
setState(() {});
});
// 4. 执行动画
controller.forward();
}
@override Widget build(BuildContext context) { return Center( Icon(Icons.favorite, color: Colors.red, size: animation.value), ); } }
- AnimationController具有控制动画的方法:
- .forward()可以正向执行动画
- .reverse()可以反向执行动画
- .dispose()用来释放动画资源(在不使用时需要调用该方法,否则会造成资源泄露)
- .stop()用来停止动画运行
**Tween**
- 简介
- AnimationController动画生成值得默认区间是0.0到1.0,如果希望使用不同得区间,或不同得数据类型,需要使用Tween(补间动画)
- Tween得唯一职责就是定义从输入范围到输出范围得映射。
- 列如:颜色区间是0到255
- Tween
- Tween<double>(begin; 起始值, end: 结束值);
- ColorTween(begin: Colors.white, end: Colors.black);
**CurvedAnimation**
- 简介
- 动画执行得速度有多种(匀速、先快后慢或先慢后快)这里的速度称为动画曲线
- CurvedAnimation的目的是为了AnimationController添加动画曲线
- 组件
- CurvedAnimation(parent: controller, curve: Curves.easeIn)
- parent(动画控制器对象)
- curve(正向执行的动画曲线)
- reverseCurve(反向执行的动画曲线)
- Curves
- 动画曲线:[https://api.flutter.dev/flutter/animation/Curves-class.html](https://api.flutter.dev/flutter/animation/Curves-class.html)
**步骤**
- 创建动画控制器
- controller = AnimationController(duration, vsync多个动画的)
- 创建动画
- 动画曲线(CurvedAnimation)
- 补间动画(Tween)
- 监听动画
- addListener() 监听动画生成值
- addEventListener() 监听动画状态
- 执行动画
- controller.forward() 正向执行
- controller.reverse() 方向执行
**交织动画**
- what
- 交织动画是由多个单一动画叠加而成的复杂动画
- 列如:组件变化可能涉及高度、宽度、颜色、透明度、位置等等。
- 需要给每个动画设置间隔时间
- Transform(对组件进行矩阵变化)
- 平移:Transform.translate()
- 旋转:Transform.rotate()
- 缩放:Transform.scale()
**Hero动画**
- Hero动画用来实现跨页面的动画效果
- 在不同页面中,声明一个共享组件(Hero)
- 由于共享组件在不同页面中的位置、外观等不同,路由切换时,形成动画效果
- 如何实现
- 在页面A中定义起始Hero组件(source hero),声明tag
- 在页面B中定义目标Hero组件(destination hero),绑定相同的tag
- 页面跳转时,通过Navigator,传递tag
- Hero组件
- tag(路由切换时,共享组件的标记)
- child(声明子组件)
**多语言(国际化)**
- 国际化(internationalization简称i18n)
- 终端(手机)系统语言切换时,Flutter应用的跟随切换
- 内容
- 组件(Widget)国际化
- 列如:日历,弹窗等常用组件的国际化
- 文本国际化(包括文本顺序)
- 自定义文本国际化
**组件国际化**
- 在pubspec.yaml中引入flutter_localizations
- 安装包:flutter pub get(VS Code中自动保存安装)
- 设置MaterialApp
- import 'package:flutter_localizations/flutter_localizations.dart';
- localizationsDelegates(指定哪些组件需要国际化)
```dart
localizationsDelegates: [
// 本地化代理
CustomLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
- supportedLocales(指定需要支持哪些语言)
supportedLocales: [
const Locale('en', 'US'),
const Locale('zh', 'CN')
]
- 查看组件效果
- 在模拟器上,将语言设置为中文
文本多语言
- 创建本地化类
- CustomLocalizations
- 创建本地化类的代理
- CustomLocalizationsDelegate extends LocalizationsDelegate
- isSupported(当前本地化,是否在有效的语言范围内)
- shouldReload(本地化重新构建时,是否调用load方法,加载本地化资源)
- load(语言发生变更时,加载对应的本地化资源)
- CustomLocalizationsDelegate extends LocalizationsDelegate
- 使用本地化类
- CustomLocalizations.delegate ```dart import ‘package:flutter/foundation.dart’; import ‘package:flutter/material.dart’;
class CustomLocalizations { final Locale locale;
CustomLocalizations(this.locale);
static Map
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
Future
@override
bool shouldReload(covariant LocalizationsDelegate
**加载语言包**
- 检测当前语言
- localeResolutionCallback
- locale.languageCode(语言代码,列如:en、zh)
- locale.countryCode(国家代码,列如:US、CN)
```dart
localeResolutionCallback: (locale, supportedLocales) {
print('deviceLocale: $locale');
print('languageCode: ${locale.languageCode}');
print('countryCode: ${locale.countryCode}');
for (var supportedLocale in supportedLocales) {
if (supportedLocale.languageCode == locale.languageCode &&
supportedLocale.countryCode == locale.countryCode) {
return supportedLocale;
}
}
return supportedLocales.first;
},
- 设置语言包
- 创建语言文件
- 在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)获取上下文中的主题信息
- ThemeData
适配终端
- 声明不同的主题
- CustomTheme
- 使用主题
- import ‘CustomTheme.dart’;
- theme: CustomTheme.lightTheme,
- darkTheme: CustomTheme.darkTheme,
- theme: ThemeData.light(),
- darkTheme: ThemeData.dark()
查看效果
- 声明路由处理器 ```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(); });
- 声明路由
```dart
// Global.dart
import 'package:flutter/material.dart';
import 'package:fluro/fluro.dart';
class G {
// 路由
static FluroRouter router = FluroRouter();
}
// main.dart
import 'package:flutter/material.dart';
import 'package:fluro/fluro.dart';
import 'pages/index.dart';
import 'routes/Routes.dart';
import 'utils/Global.dart';
void main() {
// 初始化路由
FluroRouter router = new FluroRouter();
Routes.configureRoutes(router);
// 初始化路由放到全局组件中
G.router = router;
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
// home: Index(),
// 动态路由
onGenerateRoute: G.router.generator,
initialRoute: '/');
}
}
- 使用路由
ElevatedButton(
onPressed: () {
G.router.navigateTo(context, '/login');
},
child: Text('跳转到登录页')
)
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
```