Flutter小记
2021-01-21 本文已影响0人
91阿生
0.关于AppBar中leading
如果没有leading,automaticallyImplyLeading为true,就会默认返回箭头
如果 没有leading 且为false,空间留给title
如果有leading,automaticallyImplyLeading 这个参数就无效了
1.关于ElevatedButton
image.pngElevatedButton(
child: Text("立即体验"),
style: ButtonStyle(
foregroundColor: MaterialStateProperty.all(Color(0xFF535149)),
backgroundColor: MaterialStateProperty.all(ColorFit.mainColor),
textStyle: MaterialStateProperty.all(TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold
)),
shape: MaterialStateProperty.all(RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8)
)),
side: MaterialStateProperty.all(BorderSide(color: Colors.red, width: 2))),
onPressed: () { },
)
2.关于initState中拿不到context
解决:
Future.delayed(Duration.zero, () {
// 延迟0秒,异步执行
Navigator.of(context).pushReplacementNamed(MainPage.routeName);
});
3.关于PageView使用切换图片时,图片之间会有短暂的背景显示
解决:
// Implicit:含蓄的
设置属性 allowImplicitScrolling: true
4.关于取消scroller边缘弹簧效果
解决:
设置属性 physics: ClampingScrollPhysics()
5.关于设置命名路由问题
描述:设置命名路由时,主路由设置成 '/' 路由A,其他所注册的路由命名为 '/xxx'(非'/'),则系统会默认初始路由设置成由 '/'命名的路由A,这样在使用push替换路由(pushReplacementNamed)时,导航栏上会显示出返回按钮(如果此路由有导航栏),或左侧边缘可以拉回到主路由A页面。
【明明在MaterialApp中设置的initialRoute:为引导页/Launch页,但系统还是会默认初始路由为 '/'的主路由。】
解决:
可能原因注册其他路由时,其他路由的命名都为 / 开头;
例如像 引导页/Launch页 路由命名时,前面不用加 / 这样就正常了。
建议:不是经常使用到的页面,则路由命名可以不添加 /
6.关于全局消除水波纹效果,长按水波纹效果
解决:
theme: ThemeData(
splashColor: Colors.transparent, // 全局设置点击水波纹颜色, 去除长按不放, 水波效果
highlightColor: Colors.transparent // 全局去除点击的水波纹效果
)
7. TabBar() + TabBarView() + TabController配合
TabBar:设置标题,设置指示器样式等
TabBarView:存放标题对应的页面
TabController:使得 TabBar 与 TabBarView进行关联
选择栏.png
7. NestedScrollView 与 CustomScrollView
NestedScrollView:用来处理复杂情况下的滑动应用场景,如向上滑动视图时,要折叠隐藏一部分内容,这时候就需要使用到 NestedScrollView 与 SliverAppBar 的结合使用。
CustomScrollView:用来处理更为复杂的布局,可以将SliverAppBar,SliverList和SliverGrid SliverPadding SliverToBoxAdapter SliverPersistentHeader, SliverFillRemaining,SliverFillViewport组合等来使用。
8. 关于TextField 获取焦点 + 取消焦点
①、创建FocusNode实例aNode,并设置对应TextField的属性focusNode: aNode
②、获取焦点:FocusScope.of(context).requestFocus(aNode);
③、失去焦点:aNode.unfocus();
9. 回收键盘操作
SystemChannels.textInput.invokeMethod("textInput.hide");
10. 关于键盘监听操作
1、使用 with WidgetsBindingObserver 绑定监听
2、由于键盘开启后,应用视图尺寸会改变,则会被 WidgetsBindingObserver 监听到, 就会回调走此函数
@override
void didChangeMetrics() {}
@override
void didChangeMetrics() {
super.didChangeMetrics();
// 当键盘开启后, 界面会往上, 这里绑定监听界面缩小
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
// 获取底部被遮挡的高度
double keybordHeight = MediaQuery.of(context).viewInsets.bottom;
print("键盘高度: $keybordHeight");
// 判断
if (keybordHeight == 0) { // 键盘收起状态
} else {
}
});
}
11. 关于去处导航栏左侧自带返回按钮
appBar: AppBar(
automaticallyImplyLeading: false,
),
12. 关于dart中math函数
int i = -1; //定义一个整型变量i
double j = 2.1; //定义一个小数j
print(i.abs());//求i的绝对值,打印 ‘1’
print(j.ceil());//求j的向上最大整数,打印'3'
print(j.floor());//求j的向下的最大整数,打印'2'
print(j.round());//求离j最近的整数,四舍五入,打印'2'
print(j.truncate());//截取掉小数点取整,打印'2'
double j = 2.6;//验证小数位超过0.5的情形
print(j.round());//求离j最近的整数,四舍五入,打印'3'
print(j.truncate());//截取掉小数点取整,打印'2'
print(j.clamp(1,3));//如果j再1-3之间则返回 j,这里打印j的值 ‘2.6’;否则返回离其最近的边界值。
print(j.clamp(3,4));//打印‘3’,原理同上
print(j.clamp(1,2));//打印‘2’,原理同上
//保留n 位小数: .toStringAsFixed(n)
double j = 2.6;
String rs = j.toStringAsFixed(2) = "2.60";
1.toStringAsFixed(3); // 1.000
(4321.12345678).toStringAsFixed(3); // 4321.123
(4321.12345678).toStringAsFixed(5); // 4321.12346
123456789012345.toStringAsFixed(3); // 123456789012345.000
10000000000000000.toStringAsFixed(4); // 10000000000000000.0000
5.25.toStringAsFixed(0); // 5
13. 关于flutter中List既能获取value,也能获取下角标index
例子:final List<String> _titles = ['2021', '2020', '2019', '2018', '2017', '2016'];
...
tabs: titles.asMap().entries.map((item) {
return Tab(
child: Container(
child: Text('$(item.value) === $item.key'),
),
);
}).toList()
14. 关于flutter中拦截导航栏返回事件
class SearchPage extends StatelessWidget {
static const String routeName = '/search';
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
print('true:可点击返回上一个界面;false:点击返回效果被禁用');
return false;
},
child: Scaffold(
appBar: AppBar(
title: Text(''),
),
body: Center(
child: Text(''),
),
),
);
}
}
15. 关于flutter中关于导航栏左侧宽度不够问题
实现如下图:
image.png
AppBar(
elevation: 1.0,
automaticallyImplyLeading: false,
title: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Image.asset(ImageTool.loadOthersImgPath('other_back_dark')),
Text(widget.navTitle, style: TextStyle(
fontSize: 14,
color: Colors.black
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
)
],
),
),
16. 关于flutter中使用 shared_preferences 出现 Unhandled Exception: Null check operator used on a null value 问题
解决:
void main() {
WidgetsFlutterBinding.ensureInitialized();
}
17. 关于flutter中查询 文本中共有多少个换行,并替换换行符为空格
/// 换行符个数:
final numLines = '\n'.allMatches(content).length + 1;
/// \n 替换成 空格" "
String rsContent = model.content.replaceAll(RegExp(r"\n"), " ");
18. 关于监听一个界面的 pop / push (WidgetsBindingObserver)
image.png代码:
/* 用于监听 每个界面的 push pop 组件出现或者消失的回调,主要是要靠路由的监听 */
import 'package:flutter/material.dart';
class AppRouteObserver {
//这是实际上的路由监听器
static final RouteObserver<ModalRoute<void>> _routeObserver = RouteObserver<ModalRoute<void>>();
//这是个单例
static AppRouteObserver get shared => AppRouteObserver();
static AppRouteObserver? _instance;
factory AppRouteObserver() {
return _instance ??= AppRouteObserver._internal();
}
AppRouteObserver._internal() {}
RouteObserver<ModalRoute<void>> get routeObserver => _routeObserver;
}
使用:
⑴
。。。 with WidgetsBindingObserver
⑵
@override
void initState() {
WidgetsBinding.instance?.addObserver(this);
super.initState();
}
⑶
@override
void didChangeDependencies() {
super.didChangeDependencies();
//路由订阅
AppRouteObserver.shared.routeObserver
.subscribe(this, ModalRoute.of(context)!);
}
⑷
@override
void didPush() {
//当前页面显示时
print("哈哈didPush");
super.didPush();
}
@override
void didPushNext() {
//当前页面 push 到另一个页面
print("哈哈didPushNext");
super.didPushNext();
}
@override
void didPop() {
//当前的页面被pop.
print("哈哈didPop");
super.didPop();
}
@override
void didPopNext() {
//另一个页面 pop 到当前页面时.
print("哈哈didPopNext");
super.didPopNext();
}
⑸
@override
void dispose() {
AppRouteObserver.shared.routeObserver.unsubscribe(this);
WidgetsBinding.instance?.removeObserver(this);
super.dispose();
}