在项目开始的时候就确定好APP的结构能够为我们创造良好的用户体验,而正确的使用导航系统能够让用户在APP内更快速的找到自己需要的信息。
Scaffold是Flutter中Material Design使用的最广泛的widget之一,我们本节将来学一下它的使用方法。
Scaffold的使用
Scaffold包含了我们开发中需要用到所有的的可视布局组件,包括:
- AppBar
- BottomSheet
- BottomNavigationBar
- Drawer
- FloatingActionButton
- SnackBar
Scaffold还包含了很多其他功能可供开发者直接使用,有待我们进一步的探索,下图是Scaffold所包含的一些组件的示意图:
Flutter中的Widget相关文档
https://flutter.dev/docs/development/ui/widgets/material
主页Widget
在Flutter中,一切都是widget。在开发一个大型APP的时候,我们通过运用各种widget及其组合来完成开发工作,为了避免过于复杂的widget嵌套,保证代码的可读性,我们通常会在不同的文件中来完成不同widget的代码。
现在我们就先来完成Fooerdlich APP的主页widget的开发。
Scaffold需要处理各种状态的变化,我们通过继承StatefulWidget来实现我们的主页widget。
新建home.dart文件作为主页widget,将原main.dart文件下的相关代码移植过来,代码如下:
import 'package:flutter/material.dart';
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
// TODO: Add state variables and functions
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'Fooderlich',
//2.更改了AppBar上的文字样式
style: Theme.of(context).textTheme.headline6,
),
),
// TODO: Show selected tab
body: Center(
child: Text('Let\'s get cooking ! ',
//3.更新了中间的文字的样式
style: Theme.of(context).textTheme.headline1)),
// TODO: Add bottom navigation bar
);
}
}
新的widget只是简单的更改了一下文字的样式,还有更多的功能待完成.
现在在main.dart中导入home.dart后,将Fooderlich的build方法中返回值修改为:
return MaterialApp(
//使用自定义主题
theme: theme,
title: 'Fooderlich',
home: const Home(),
);
添加底部导航栏
现在我们在APP的底部添加一个导航栏,方便用户在不同的模块之间进行切换,我们使用的widget是
BottomNavigationBar,在home.dart文件中替换TODO: Add bottom navigation bar为如下代码:
//定义底部导航栏
bottomNavigationBar: BottomNavigationBar(
//设置被选中时的颜色
selectedItemColor: Theme.of(context).textSelectionTheme.selectionColor,
//TODO: Set selected tab bar
//定义导航栏内容
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.card_giftcard),
label: 'Card1',
),
BottomNavigationBarItem(
icon: Icon(Icons.card_giftcard),
label: 'Card2',
),
BottomNavigationBarItem(
icon: Icon(Icons.card_giftcard),
label: 'Card3',
),
],
),
添加底部导航栏后的效果如图:
当然,现在点击这些选项还没有什么效果,我们下面需要实现点击的实际功能,我们用变量记录用户点击的位置,然后根据点击的位置来进行跳转.
在TODO: Add state variables and functions 这个地方添加如下代码:
//记录点击的位置
int _selectedIndex = 0;
//暂时实现的点击跳转的目标页面,后面将替换为实际的Card widget
static List<Widget> pages = <Widget>[
// TODO: Replace with Card1
Container(color: Colors.red),
// TODO: Replace with Card2
Container(color: Colors.green),
// TODO: Replace with Card3
Container(color: Colors.blue)
];
//处理导航栏被点击的事件, setState()方法会使系统重新渲染该widget
//我们在这个里面更新了用户点击的位置数据
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
到 TODO: Show selected tab的位置,替换为如下代码,以便在点击的时候展示对应的UI:
body: pages[_selectedIndex],
然后进入到BottomNavigationBar中的 TODO: Set selected tab位置,添加点击效果的回调:
//当前被选中的item的位置,将会被高亮显示
currentIndex: _selectedIndex,
//用户点击item时,将会调用该方法,更新_selectedIndex的值,然后重新渲染该widget
onTap: _onItemTapped,
因为涉及到Widget状态的变化,所有hot reload无法展示APP的新变化了,需要直接运行或者hot restart才能看到APP的变化.
点击下方的导航栏,可以看到界面颜色发生了变化,接下来我们将会把这些单纯的颜色展示界面变成漂亮的Card.