本文首发于微信公众号「后厂技术官」
ReactNative入门系列
React Native组件
Flutter基础系列
前言
在上一篇 Flutter基础(五)Material组件最佳入门(前篇)中,我介绍了Material组件的MaterialApp、Scaffold、AppBar,这篇文章接着介绍Material组件中的BottomNavigationBar、TabBar、Drawer。
1.BottomNavigationBar
BottomNavigationBar是底部的导航栏,用于在3到5个的少量视图中进行选择。一般情况下,导航栏的选项卡由文本标签、图标或两者结合的形式组成。
底部导航栏通常与javaScaffold结合使用,它会作为Scaffold.bottomNavigationBar参数。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget { static const String _title = 'Flutter Code Sample';
@override Widget build(BuildContext context) { return MaterialApp( home: MyStatefulWidget(), ); } }
class MyStatefulWidget extends StatefulWidget { MyStatefulWidget({Key key}) : super(key: key);
@override _MyStatefulWidgetState createState() => _MyStatefulWidgetState(); }
class _MyStatefulWidgetState extends State<MyStatefulWidget> { int _selectedIndex = 0; static const List<Widget> _widget = <Widget>[ Text( 'Index 0:首页', ), Text( 'Index 1: 通讯录', ), Text( 'Index 2: 设置', ), ];
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('BottomNavigationBar示例'), ), body: Center( child: _widget.elementAt(_selectedIndex), ), bottomNavigationBar: BottomNavigationBar( items: const <BottomNavigationBarItem>[ BottomNavigationBarItem( icon: Icon(Icons.home), title: Text('首页'), ), BottomNavigationBarItem( icon: Icon(Icons.contacts), title: Text('通讯录'), ), BottomNavigationBarItem( icon: Icon(Icons.build), title: Text('设置'), ), ], currentIndex: _selectedIndex, selectedItemColor: Colors.amber, onTap: _onItemTapped, ), ); } void _onItemTapped(int index) { setState(() { _selectedIndex = index; }); } }
|
由于使用的Widget需要在Widget的生命周期中改变状态,因此MyStatefulWidget继承了StatefulWidget。注释1处的createState方法会为此Widget创建可变状态。注释2处的onTap属性会在点击其中一个选项卡时调用,它的值由_onItemTapped方法定义,在这个方法中设置当前的索引赋值给_selectedIndex,这样通过_selectedIndex的值就可以切换选项卡了。实现的效果如下所示,可以通过点击选项卡来切换界面。
2.TabBar
TabBar用于显示水平的选项卡,和Android中的TabLayout类似。TabBar通常需要配合TabBarView和TabController。其中TabBarView用于显示与当前所选的选项卡对应的Widget视图;TabController顾名思义就是TabBarView和TabBar的控制器,是这两个Widget的桥梁。实现TabController有两种方式,一种是用系统的DefaultTabController,另一种是自定义TabController。
2.1 使用DefaultTabController
DefaultTabController这种方式方便快捷,直接新建一个DefaultTabController就可以了。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: MyTabController(), ); } } class MyTabController extends StatelessWidget { @override Widget build(BuildContext context) { return DefaultTabController( length: 3, child: Scaffold( appBar: AppBar( title: Text('DefaultTabController示例'), bottom: TabBar( tabs: <Widget>[ Tab( text: '热点', ), Tab( text: '体育', ), Tab( text: '科技', ), ], ), ), body: TabBarView( children: <Widget>[ Center(child: Text('热点')), Center(child: Text('体育')), Center(child: Text('科技')), ], ), ), ); } }
|
2.2 自定义TabController
如果想要切换动画或者监听切换的交互,可以自定义TabController,需要实现SingleTickerProviderStateMixin。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: MyStatefulWidget(), ); } }
class MyStatefulWidget extends StatefulWidget { MyStatefulWidget({Key key}) : super(key: key); @override _MyStatefulWidgetState createState() => _MyStatefulWidgetState(); }
class _MyStatefulWidgetState extends State<MyStatefulWidget> with SingleTickerProviderStateMixin { TabController _tabController;
void initState() { super.initState(); _tabController = TabController(vsync: this, length: 3); }
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('自定义TabController'), bottom: TabBar( tabs: <Widget>[ Tab( text: '热点', ), Tab( text: '体育', ), Tab( text: '科技', ), ], controller: _tabController, ), ), body: TabBarView( controller: _tabController, children: <Widget>[ Center(child: Text('热点')), Center(child: Text('体育')), Center(child: Text('科技')), ], ), ); } @override void dispose() { _tabController.dispose(); super.dispose(); } }
|
和第一种使用DefaultTabController有两点不同,一个是使用了StatefulWidget,另一个是在注释1处将TabBar的controller设置为新建的TabController。运行效果如下所示,可以通过滑动界面和点击选项卡来切换界面。
3.Drawer
Drawer就是抽屉,可以实现拉出推入的效果,和Android中的DrawerLayout类似。Drawer通常与Scaffold.drawer属性一起使用,抽屉的子项通常是ListView,其第一个子项是头部,头部主要有两个Widget可以实现:
- DrawerHeader:展示基本的信息
- UserAccountsDrawerHeader:展示用户头像、用户名、Email等信息。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget { static const String _title = 'Flutter Code Sample';
@override Widget build(BuildContext context) { return MaterialApp( home: MyStatefulWidget(), ); } }
class MyStatefulWidget extends StatefulWidget { MyStatefulWidget({Key key}) : super(key: key);
@override _DrawerState createState() => _DrawerState(); }
class _DrawerState extends State<MyStatefulWidget> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Drawer例子'), ), drawer: _drawer, ); } get _drawer => Drawer( child: ListView( padding: EdgeInsets.zero, children: <Widget>[ UserAccountsDrawerHeader( accountName: Text('刘望舒'), accountEmail: Text('liuwangshu.gmail.com'), currentAccountPicture: CircleAvatar( child: Text('X'), ), ), ListTile( leading: Icon(Icons.local_post_office), title: Text('邮件'), ), ListTile( leading: Icon(Icons.settings), title: Text('设置'), ) ], ), ); }
|
跟以往例子不同的是,由于drawer属性的代码比较多,为了提高可读性,我将drawer属性的值抽取出来,通过getter的形式进行获取。注释1处可以看出Drawer的子项为ListView,ListView的通过ListTile来显示每一个列表项。注释2使用的是UserAccountsDrawerHeader,可以很轻松的设置用户的姓名、邮箱、用户图片等。效果如下图所示:
总结
加上上一篇文章,我已经介绍了Material组件中应用程序结构和导航分类中的大部分Widget,另外Material组件所包含的其他的Widget,本系列就不介绍了,想要了解的可以查看文档:https://flutter.dev/docs/development/ui/widgets/material