一.导航
1.导航栏按钮设置
Scaffold(
appBar: AppBar(
title: Text("导航栏标题"),
centerTitle: true, // 设置多个actions时, 标题会靠左边, 设置此熟悉标题会居中
actions: [ // 设置右边的 items
IconButton(icon: Icon(Icons.near_me), onPressed: null),
IconButton(icon: Icon(Icons.near_me), onPressed: null),
],
automaticallyImplyLeading: false, // 默认是系统自动实现左边的item实现导航跳转, 当页面需要手动控制时, 使用下面3个熟悉来调整
leadingWidth: 60,
leading: Icon(Icons.arrow_back),
),
body: Center(
child: Text("内容")
),
)
2.怎么present一个界面
使用fullscreenDialog实现
Navigator.of(context).push(MaterialPageRoute(fullscreenDialog: true, builder: (context){
return ThePresentedPage(); // 需要present出来的界面
}));
二.布局
1. 使用ListView时使用ListTile, 但是title和leading默认的距离太大, 调整他们之间的距离
使用transform属性调整leading的位置. 另外可以自定义cell
ListTile(
title: Transform(transform: Matrix4.translationValues(-20, 0, 0), child: Text("退出")),
leading: Icon(Icons.exit_to_app),
trailing: Icon(Icons.navigate_next),
onTap: (){print("logout")},
)
2. alignment实现(垂直居中, 水平左对齐)
来源: https://www.jianshu.com/p/a675b4d66a93
3.根据传入的动态数组创建一组widget
_buildStatusRow(String type, String status, List<String> infos) {
List<Widget> infoWidgets = [];
for (var info in infos) {
var oneInfoW = Container(
margin: EdgeInsets.only(left: 5),
padding: EdgeInsets.only(left: 5, right: 5),
decoration: BoxDecoration(
border: Border.all(color: Colors.black12, width: 0.5),
borderRadius: BorderRadius.circular(4)),
child: Text(
"$info",
style: TextStyle(fontSize: 12),
));
infoWidgets.add(oneInfoW);
}
List<Widget> rowChildren = [
Text("$type:"),
Container(width: 5),
ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(6), bottomRight: Radius.circular(6)),
child: Container(
padding: EdgeInsets.only(left: 5, right: 5),
color: Colors.orangeAccent,
child: Text(
status,
style: TextStyle(color: Colors.white, fontSize: 13, height: 1.5),
))),
];
rowChildren.addAll(infoWidgets);
return Container(
margin: EdgeInsets.only(bottom: 3), child: Row(children: rowChildren));
}
4.兄弟widget有重叠时,使用Stack布局
5.ListView显示scroll indicator
将ListView包裹在Scrollbar里面
@override
Widget build(BuildContext context) {
return Scrollbar(
child: ListView.builder(
itemCount: 50,
itemBuilder: (context, index) {
return ListTile();
})
);
}
6.监听app的生命周期
生命周期共4种, 分别是: resumed(从后台进入前台)、inactive(即将进入后台和进入前台之前, 例如iOS app在前台, 双击home键时的状态)、paused(进入后台)、detached
如果还需要其它事件,则可以用EventChannel实现
class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
@override
void dispose() {
super.dispose();
WidgetsBinding.instance.removeObserver(this);
}
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
print(state);
}
}
7.flutter键盘弹出,遮挡界面
问题:在登录注册界面会有输入框, 键盘弹出时会遮挡输入框.
解决:在原生iOS开发中, 会监听键盘弹出和隐藏事件, 然后改变界面布局. 我们使用相同的处理方法在flutter中进行处理
class _LoginPageState extends State<LoginPage> with WidgetsBindingObserver {
var _username = "";
var _pwd = "";
var _keyboardH = 0.0;
// 1.监听键盘事件
@override
void initState() {
super.initState();
_username = LoginInfoMgr.sharedMgr.username;
_pwd = LoginInfoMgr.sharedMgr.pwd;
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
WidgetsBinding.instance.removeObserver(this);
}
@override
void didChangeMetrics() {
// TODO: implement didChangeMetrics
print("did changemetrics");
super.didChangeMetrics();
WidgetsBinding.instance.addPostFrameCallback((_) {
double bottom = MediaQuery.of(context).viewInsets.bottom;
if(bottom == 0){
//关闭键盘
print("close");
setState(() {
_keyboardH = 0.0;
});
}else{
//显示键盘
print("show - $bottom");
setState(() {
_keyboardH = bottom;
});
}
});
}
// 2.根据键盘高度调整布局
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomPadding: false, // 需要设置为false, 保证widget不变形
appBar: AppBar(
title: Text("登录"),
),
backgroundColor: Colors.lightBlueAccent,
body: Stack(
children: [
_buildTopContainer(),
_buildBottomContainer()
]
),
);
}
_buildTopContainer() {
return GestureDetector(
onTap: () {FocusScope.of(context).requestFocus(FocusNode());},
child: Container(
width: MediaQuery.of(context).size.width,
height: 200,
color: Colors.lightBlueAccent,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(Icons.settings_bluetooth, size: 55, color: Colors.white70),
Container(
margin: EdgeInsets.only(top: 15),
child: Text(
"app名字",
style: TextStyle(color: Colors.white70, fontSize: 16),
)),
]),
),
);
}
// 根据键盘高度, 调整下面container的位置
_buildBottomContainer() {
var marginTop = 200 - _keyboardH/6;
marginTop = marginTop < 0 ? 0 : marginTop;
return Container(
margin: EdgeInsets.only(top: marginTop),
height: MediaQuery.of(context).size.height - 200,
child: ClipRRect(
borderRadius: BorderRadius.only(topLeft: Radius.circular(30), topRight: Radius.circular(30)),
child: Container(
color: Colors.white,
child: Column(children: [
Container(
margin: EdgeInsets.only(left: 20, right: 20, top: 35),
child: TextField(
controller: TextEditingController(text: _username),
decoration: InputDecoration(
hintText: "用户名", icon: Icon(Icons.account_balance)),
onChanged: (value) {
_username = value;
},
)),
Container(
margin: EdgeInsets.only(left: 20, right: 20, top: 10),
child: TextField(
controller: TextEditingController(text: _pwd),
obscureText: true,
decoration: InputDecoration(hintText: "密码", icon: Icon(Icons.security),),
onChanged: (value){
_pwd = value;
},
)),
Expanded(
child: Center(
child: Container(
width: MediaQuery.of(context).size.width * 0.7,
height: 45,
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(22.5)),
child: RaisedButton(
color: Colors.lightBlueAccent,
textColor: Colors.white,
child: Text("登录"),
onPressed: _doLogin
)
)
))),
]),
),
));
}
}
8.flutter Tab搭建
import 'package:flutter/material.dart';
class TabCtlPage extends StatefulWidget {
@override
State<StatefulWidget> createState() => _TabCtlPageState();
}
class _TabCtlPageState extends State<TabCtlPage> {
var _pageController = PageController();
var _currentIdx = 0;
_changedIndex(index) {
print("index = $index");
if (_currentIdx == index) {
print("return");
return;
}
_pageController.jumpToPage(index);
setState(() {
_currentIdx = index;
});
}
var _pages = List<Widget>();
@override
void initState() {
// TODO: implement initState
super.initState();
_pages = [
HomePage(),
MinePage()
];
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: PageView(
physics: NeverScrollableScrollPhysics(),
controller: _pageController,
children: _pages,
),
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(icon: Icon(Icons.hearing), title: Text("首页")),
BottomNavigationBarItem(icon: Icon(Icons.settings), title: Text("我的")),
],
onTap: _changedIndex,
currentIndex: _currentIdx,
),
);
}
}
网友评论