1.Android设置沉浸式
// SystemUiOverlayStyle用于覆盖系统navigationBar,statusBar等样式
// SystemChrome 控制操作系统图像界面与操作系统交互类
// SystemChrome.setPreferredOrientations: 设置横竖屏
// SystemChrome.setSystemUIOverlayStyle():// 设置状态栏和导航栏目
// SystemChrome.setEnabledSystemUIOverlays() 对状态栏的操作:是否隐藏状态栏或者三大金刚键,常用于键盘弹出时候,隐藏三大金刚键
if (Platform.isAndroid) {
SystemUiOverlayStyle systemUiOverlayStyle = SystemUiOverlayStyle(statusBarColor: Colors.transparent);
SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle);
}
2.precacheImage
在Flutter中,加载本地图片会存在一个加载过程。比如点击图标做图标的切换时,那么首次会发生闪动的情况。尤其是做类似引导页这类需求是,通过左右滑动切换图片时会发生比较明显的白屏一闪而过。
解决方法:使用precacheImage,将图像预存到图像缓存中,如果图像稍后被使用,他会被加载得更快。
precacheImage(AssetImage("images/logo.png"), context);
3.设置状态栏的颜色
// 方式一:
appbar: AppBar(
title: Text('.....'),
brightness: Brightness.dark,
);
// 方式二:(不使用AppBar的情况下,只需要在最外层包裹一下)
Widget build(BuildContext context) {
return AnnotatedRegion<SystemUiOverlayStyle> (
value: SystemUiOverlayStyle.light,
child: ....
)
}
4.Stack子组件设置宽高不起作用
// red不起作用
child: Container(
height: 300,
width: 300,
color: Colors.blue,
child: Stack(
children: <Widget>[
Positioned.fill(
child: Container(
height: 100,
width: 100,
color: Colors.red,
),
)
],
),
),
// 解决方案:使用Center,Align或者UnconstrainedBox包裹一下,例如:
Positioned.fill(
child: Align(
child: Container(
height: 100,
width: 100,
color: Colors.red,
),
),
)
5.default value of optional parameter must be constant
在类构造函数的时候经常会报以上异常。异常信息提示:可选参数必须为常量
class BarrageItem extends StatefulWidget {
BarrageItem({
this.text,
this.duration = Duration(seconds: 3)
});
}
// 可以这样修复
const Duration _kDuration = Duration(seconds: 3);
class BarrageItem extends StatefulWidget {
BarrageItem({
this.text,
this.duration = _kDuration
});
}
6.TextField动态获取焦点和失去焦点
// 定义
_focusNode = FocusNode();
TextField(
focusNode: _focusNode,
...
);
// 获取焦点
FocusScope.of(context).requestFocus(_focusNode);
// 失去焦点
_focusNode.unfocus();
7.创建一个圆角Button
方式一:使用FlatButton和RaiseButton
shap: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18.0),
side: BorderSide(color: Colors.red)
)
方式二:使用ClipReact
ClipReact(
borderRadius: Border.circle(40),
child: RaiseButton(
onPressed:(){},
child: Text("Button")
)
)
方式三:使用ButtonTheme
ButtonTheme(
shape: RoundedRectangleRorder(borderRadius: BorderRadius.circle(20),
child: RaiseButton(
onPressed:() {},
child: Text("....")
)
)
8.让Button充满父组件
// 方式一
SizedBox.expand(
child: RaisedButton(...)
)
// 方式二
ConstrainedBox(
contraints: const BoxConstraints(minWidth: double.infinity),
child: RaisedButton(...)
)
// 方式三
ButtonTheme(
minWidth: double.infinity,
child: MaterialButton(
onPress:(){},
child: Text('Raised Button')
)
)
9.如何给图片添加圆角
// 方式一
ClipRRect(
borderRadius: borderRadius.circular(8.0),
child: Image.network(...)
)
// 方式二
CircleAvatar(
radius: 20,
backgroundImage: NetworkImage('....')
)
// 方式三
ClipOval(
child: Image.network(
"image_url",
height: 100,
width: 100,
fit: BoxFit.cover
)
)
// 方式四
Container(
width: 100.0,
height: 150.0,
decorartion: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage('....')
),
borderRadius: BorderRadius.all(Radius.circular(8.0)),
color: Colors.redAccent
)
)
10.如何去掉TextField的下划线
InputDecoration(
border: InputBorder.none,
hintText: 'Username'
)
11.显示/隐藏控件
// 控件一
Opacity(
opacity: 0,
child: ...
)
// 控件二
Visibility(
visible:false,
child: ...
)
// 控件三
offstage(
offstage: true,
child:...
)
12.如何截取Android的返回按键并处理
WillPopScope用于处理是否离开当前页面。询问用户是否退出
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async => {
return showDialog(
context: context,
builder: (context) =>
AlertDialog(
title: Text("你确定要退出吗"),
actions: <Widget>[
RaisedButton(
child: Text('退出'),
onPressed ()=>Navigator.of(context).pop(true),
),
RaisedButton(
child: Text('取消'),
onPressed ()=>Navigator.of(context).pop(false),
),
]
)
)
},
child: Scaffold(child: ...)
)
}
快速点击两次退出
DateTime _lastQuitTime;
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async => {
if(_lastQuitTime == null || DateTime.now().difference(_lastQuitTime).inSeconds > 1) {
Scaffold.of(context)
.showSnackBar(SnackBar(content: Text('再按一次 Back 按钮退出')));
_lastQuitTime = DateTime.now();
return false;
} else {
print('退出');
Navigator.of(context).pop(true);
return true;
}
},
child: Scaffold(child: ...)
)
}
13.设置AppBar的Height
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Example',
home: Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(50.0), // here the desired height
child: AppBar(
// ...
)
),
body: // ...
)
);
}
}
14.Column的子控件底部剧中,左对齐
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
//your elements here
],
);
15.Illegal percent encoding in URI
使用fluro路由为下一个页面传参,且参数为中文时报的这个错误。解决方案,在url中使用中文参数时候,使用Uri.encodeComponent转下码就可以了。
Application.router.navigateTo(context, '$routeName?title=${Uri.encodeComponent(title)} ', transition: TransitionType.inFromRight);
16.Vertical viewport was given unbounded height
这个bug是在column中使用ListView出现的。解决方案是在ListView组件中使用shrinkWrap属性就可以了
return Column(
children: <Widget>[
ListView.builder(
itemCount: _datalist.length,
itemBuilder: _buildItem,
// 使用shrinkWrap
shrinkWrap: true,
),
],
);
17.隐藏键盘
// 隐藏键盘
FocusScope.of(context).unfocus();
TabBar切换导致重建build问题(不知道为啥我的没用,先记录着,后续改进)
// 解决方案:设置PageStorageKey
var _onePageKey = PageStorageKey("onePages");
var _twoPageKey = PageStorageKey("twoPages");
TabBarView(
controller: _controller,
children: <Widget>[
_onePage(_onePageKey),
_twoPage(_twoPageKey)
]
)