# 1. Button 限制宽高
使用 SizeBox 进行包裹。
Widget _arrowIcon = SizedBox(
width: duSetWidth(18.0),
child: FlatButton(
padding: EdgeInsets.all(0),
onPressed: () {
print('_arrowIcon tap');
},
child: Icon(
IconFont.iconmore,
color: AppColors.grayThirdColor,
size: duSetFontSize(14),
),
),
);
# 2.获取目标 widget 相关信息
使用 GlobalKey()
// 定义变量
GlobalKey _Key = GlobalKey();
// 绑定 widget
Center(
key: _Key,
child: Text('content')
);
// 使用
RenderBox _box = _alphabetListKey?.currentContext?.findRenderObject();
_box.localToGlobal(Offset.zero); // offset
// ...
# 3.沉浸式状态栏
void _statusBar([String color]) {
// 白色沉浸式状态栏颜色 白色文字
SystemUiOverlayStyle light = SystemUiOverlayStyle(
systemNavigationBarColor: Color(0xFF000000),
systemNavigationBarDividerColor: null,
/// 注意安卓要想实现沉浸式的状态栏 需要底部设置透明色
statusBarColor: Colors.transparent,
systemNavigationBarIconBrightness: Brightness.light,
statusBarIconBrightness: Brightness.light,
statusBarBrightness: Brightness.dark,
);
// 黑色沉浸式状态栏颜色 黑色文字
SystemUiOverlayStyle dark = SystemUiOverlayStyle(
systemNavigationBarColor: Color(0xFF000000),
systemNavigationBarDividerColor: null,
/// 注意安卓要想实现沉浸式的状态栏 需要底部设置透明色
statusBarColor: Colors.transparent,
systemNavigationBarIconBrightness: Brightness.light,
statusBarIconBrightness: Brightness.dark,
statusBarBrightness: Brightness.light,
);
"white" == color?.trim()
? SystemChrome.setSystemUIOverlayStyle(light)
: SystemChrome.setSystemUIOverlayStyle(dark);
}
# 4.获取顶部状态栏高度
- MediaQuery.of(context).padding.top
- MediaQueryData.fromWindow(window).padding.top
# 5.安全区域,比如:iphone 12等全面屏底部遮挡问题
- SafeArea
# 6.国际化初始化生命周期问题
问题:在 initState 直接调用 DemoLocalizations.of(context).all
原因:initState 生命周期的作用主要是将当前的 state 与上下文 buildContext 产生关联,此时的上下文还不能使用。
解决方案:
- initState 添加异步逻辑
Future.delayed(Duration.zero, () { // ... });
- 放 didChangeDependencies 生命周期
# 7.切换 tab,addListener 触发两次
点击切换tab的时候执行了一个动画效果,滑动切换的时候是没有的,在这个过程中触发了一次Listener,所以触发了两次addListener方法。
解决方案:在 addListener 中添加判断
if(_newsTabController.index == _newsTabController.animation.value) { //... }
if(_newsTabController.indexIsChanging) { //... }
# 8.stack 溢出部分点击失效问题
如下图:蓝色区域为父级 stack 容器,灰色容器(1+2)为 stack 子级样式,由于 2 溢出父级容器,出现问题:2 点击事件不生效。
解决办法:更改布局,父级容器包裹整个区域,不让其溢出。
# 9.vscdoe 多渠道 flavor 配置
根目录添加 .vscode/launch.json 配置文件,添加配置:
{
"version": "xxx",
"configurations": [
{
"name": "wapcar",
"request": "launch",
"type": "dart",
"args": [
"--flavor",
"wapcar"
]
},
{
"name": "autofun",
"request": "launch",
"type": "dart",
"args": [
"--flavor",
"autofun"
]
}
]
}
# 10.json 序列化 (opens new window)
- 安装依赖
dependencies:
json_annotation: ^3.1.1
dev_dependencies:
build_runner: ^1.10.13
json_serializable: ^3.5.1
- 创建模型类 user.dart
import 'package:json_annotation/json_annotation.dart';
/// This allows the `User` class to access private members in
/// the generated file. The value for this is *.g.dart, where
/// the star denotes the source file name.
part 'user.g.dart';
/// An annotation for the code generator to know that this class needs the
/// JSON serialization logic to be generated.
()
class User {
User(this.name, this.email);
String name;
String email;
/// A necessary factory constructor for creating a new User instance
/// from a map. Pass the map to the generated `_$UserFromJson()` constructor.
/// The constructor is named after the source class, in this case, User.
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
/// `toJson` is the convention for a class to declare support for serialization
/// to JSON. The implementation simply calls the private, generated
/// helper method `_$UserToJson`.
Map<String, dynamic> toJson() => _$UserToJson(this);
}
- 执行命令 flutter pub run build_runner build 后生成 user.g.dart 文件
# 11.延迟加载库
# 12.获取屏幕宽高
double _screenHeight = MediaQuery.of(context).size.height
double _screenWidth = MediaQuery.of(context).size.width
# 13.解决 bottomNavigationBar切换 tabbar 刷新页面,原有状态消失问题
- AutomaticKeepAliveClientMixin
- IndexedStack
Scaffold(
bottomNavigationBar: _buildBottomNavigationBar(),
body: IndexedStack( // indexedStack 可以确保 tabbar 时候不刷新页面
index: _selectedIndex,
children: _contentListView,
),
);
# 14.切换 tabbar 保存状态
class _HomeRecommednedState extends State<HomeRecommedned>
with AutomaticKeepAliveClientMixin {
bool get wantKeepAlive => true; // with AutomaticKeepAliveClientMixin + 设置 wantKeepAlive 为 true,确保顶部切换 tabbar 保存 state
}
# 15.FutrueBuilder / StreamBuilder
作用:异步 UI 更新。两者都可以用于接收异步事件数据。
区别:
futureBuilder
只有一个响应,类似于 js 中的 Promise。
streamBuilder
可以接收多个异步操作的结果,常用于多次读取数据的异步任务场景。
# 16. Flutter 布局约束
链接:https://flutter.cn/docs/development/ui/layout/constraints