前言
在现代移动应用中,良好的导航体验是提升用户满意度的关键因素。Flutter提供了多种导航组件,包括底部导航栏(BottomNavigationBar)、侧边栏(Drawer)和顶部导航栏(AppBar),使开发者能够轻松创建直观且高效的应用界面。本文档将详细介绍如何在Flutter应用中实现这些导航组件,涵盖以下内容:
底部导航栏
简单使用
bottomNavigationBar: BottomNavigationBar( items:[ BottomNavigationBarItem( icon:Icon(Icons.home), label:"hello" ), BottomNavigationBarItem( icon:Icon(Icons.category), label:"分类" ), BottomNavigationBarItem( icon:Icon(Icons.settings), label:"设置" ), ] ),
属性
bottomNavigationBar: BottomNavigationBar( // 图标大小 iconSize: 40, // 图标 颜色 fixedColor: Colors.red, // 如果 底部 按钮 四个或以上 需要使用到 type: BottomNavigationBarType.fixed, // currentIndex 当前 显示 的 下标 currentIndex: _currentIndex, // 点击事件 onTap: (index){ // 动态 的 需要加上 setState setState(() { _currentIndex=index; }); }, // items 放 图标 items:const [ BottomNavigationBarItem( icon:Icon(Icons.home), label:"首页" ),
需要 加控制器
demo
先创建一个pages 文件夹
里面再创建一个tabs 文件夹
放入 home ,setting,user,category 等dart
tabs 文件夹下面 有 个 tabs.dart
user.dart 其他 的 都 为一样
import 'package:flutter/material.dart'; class UserPage extends StatefulWidget { const UserPage({Key? key}) : super(key: key); @override State<UserPage> createState() => _UserPageState(); } class _UserPageState extends State<UserPage> { @override Widget build(BuildContext context) { return Center( child: Text("用户"), ); } }
import 'package:flutter/material.dart'; import './tabs/home.dart'; // 1 import './tabs/category.dart'; //2 import './tabs/setting.dart'; // 3 import './tabs/user.dart'; class Tabs extends StatefulWidget { const Tabs({Key? key}) : super(key: key); @override State<Tabs> createState() => _TabsState(); } class _TabsState extends State<Tabs> { // 定义一个可 用来 记录 点击按钮的 变量 int _currentIndex=0; // 将 4 个 组件 放入 到一个 list 中 final List <Widget> _pages= const [ HomePage(), CategoryPage(), SettingPage(), UserPage() ]; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('flutter demo'),), // body 为 list 数组 下标 为 记录 的变量 body: _pages[_currentIndex], // 底部 导航 bottomNavigationBar: BottomNavigationBar( // 图标大小 iconSize: 40, // 图标 颜色 fixedColor: Colors.red, // 如果 底部 按钮 四个或以上 需要使用到 type: BottomNavigationBarType.fixed, // currentIndex 当前 显示 的 下标 currentIndex: _currentIndex, // 点击事件 onTap: (index){ // 动态 的 需要加上 setState setState(() { _currentIndex=index; }); }, // items 放 图标 items:const [ BottomNavigationBarItem( icon:Icon(Icons.home), label:"首页" ), BottomNavigationBarItem( icon:Icon(Icons.category), label:"分类" ), BottomNavigationBarItem( icon:Icon(Icons.settings), label:"设置" ), BottomNavigationBarItem( icon:Icon(Icons.people), label:"用户" ), ] ), ); } }
将 这个 引入 到 main.dart 中
import 'package:flutter/material.dart'; import './pages/tabs.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( title: 'flutter demo', theme: ThemeData(primarySwatch: Colors.blue), home: const Tabs(), ); } }
与按钮一起用
floatingActionButton
主要 调一下 位置 和 改变 颜色 与 显示 页面
floatingActionButton: Container( // 调整上下 位置 margin: const EdgeInsets.only(top: 22), // 按钮 大小 height: 62, width: 62, padding: const EdgeInsets.all(3), // 修饰边框 decoration: BoxDecoration( color: Colors.black12, borderRadius: BorderRadius.circular(30)), child: FloatingActionButton( // 用 三元运算 符 改变 显示 颜色 // 当 为 两种 状态 时 多用 这个 backgroundColor: _currentIndex == 2 ? Colors.red : Colors.yellow, child: Icon(Icons.add), onPressed: () { setState(() { _currentIndex = 2; }); }, ), ), // 改变 按钮 位置 floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
使用图片
// items: [ // new BottomNavigationBarItem( // label: "微信", // icon: _currentIndex == 0 // ? ClipOval( // child: Image.asset( // "images/noodle.jpg", // width: 32.0, // height: 28.0, // )) // : ClipOval( // child: Image.asset( // "images/sleep.webp", // width: 32.0, // height: 28.0, // ), // )), // new BottomNavigationBarItem( // label: "通迅录", // icon: _currentIndex == 0 // ? Image.asset( // "images/noodle.jpg", // width: 32.0, // height: 28.0, // ) // : Image.asset( // "images/sleep.webp", // width: 32.0, // height: 28.0, // ), // ), // new BottomNavigationBarItem( // label: "发现", // icon: _currentIndex == 0 // ? Image.asset( // "images/noodle.jpg", // width: 32.0, // height: 28.0, // ) // : Image.asset( // "images/sleep.webp", // width: 32.0, // height: 28.0, // ), // ), // new BottomNavigationBarItem( // label: "我的", // icon: _currentIndex == 0 // ? Image.asset( // "images/noodle.jpg", // width: 32.0, // height: 28.0, // ) // : Image.asset( // "images/sleep.webp", // width: 32.0, // height: 28.0, // ), // ), // ],
AppBar
简单属性
appBar: AppBar( // 前面的 左边 leading: IconButton( icon: Icon(Icons.menu), onPressed: () { print("left icon "); }, ), // 背景颜色 appbar 的 背景 颜色 backgroundColor: Colors.red, // 后边的 右边 actions: [ IconButton( onPressed: () { print("search icon"); }, icon: Icon(Icons.search)), IconButton( onPressed: () { print("more icon"); }, icon: Icon(Icons.more_horiz)), ],
实现 小功能
定义一个 controller late TabController _tabController; 初始化 @override void initState(){ super.initState(); _tabController=TabController(length: 4, vsync: this); } 下面 添加 bottom: TabBar()
bottom: TabBar( // 可以 滑动 isScrollable: true, controller: _tabController, indicatorColor: Colors.white, // 下面的颜色 indicatorWeight: 2, // 下面的 形状 大小 indicatorPadding: EdgeInsets.all(5), // indicatorSize: TabBarIndicatorSize.label, // 和文字 的长度 // 可在 里面 配置 属性 indicator: BoxDecoration( color: Colors.blue, borderRadius: BorderRadius.circular(10), ), // 背景 颜色 labelColor: Colors.yellow, // 这个 改变 文字 颜色 labelStyle: TextStyle( fontSize: 14 ), unselectedLabelStyle: TextStyle( fontSize: 12 ), unselectedLabelColor: Colors.white, // 未选中 的颜色 tabs: [ Tab( child: Text("fllowing"), ), Tab( child: Text("hot"), ), Tab( child: Text("video"), ), Tab( child: Text("video"), ), ], ), title: Text('Flutter App'), ),
body
放 TabBarView
记得 放 controller 上面 已经 配置好
放children
body: TabBarView( controller: _tabController, children: [ // 有顺序 ListView( children: [ ListTile( title: Text('i am fllowing list'), ), ], ), ListView( children: [ ListTile( title: Text('i am hot list'), ), ], ), ListView( children: [ ListTile( title: Text('i am video list'), ), ], ), ListView( children: [ ListTile( title: Text('i am video list'), ), ], ), ], ),
所有代码
import 'package:flutter/material.dart'; import './pages/tabs.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, // 将标题 上的 debug 删除 title: 'flutter demo', theme: ThemeData(primarySwatch: Colors.blue), home: const HomePage(), ); } } class HomePage extends StatefulWidget { const HomePage({Key? key}) : super(key: key); @override State<HomePage> createState() => _HomePageState(); } class _HomePageState extends State<HomePage> with SingleTickerProviderStateMixin { late TabController _tabController; @override void initState() { super.initState(); _tabController = TabController(length: 4, vsync: this); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Flutter App'), // 前面的 左边 leading: IconButton( icon: Icon(Icons.menu), onPressed: () { print("left icon "); }, ), // 背景颜色 appbar 的 背景 颜色 backgroundColor: Colors.red, // 后边的 右边 actions: [ IconButton( onPressed: () { print("search icon"); }, icon: Icon(Icons.search)), IconButton( onPressed: () { print("more icon"); }, icon: Icon(Icons.more_horiz)), ], bottom: TabBar( // 可以 滑动 isScrollable: true, controller: _tabController, indicatorColor: Colors.white, // 下面的颜色 indicatorWeight: 2, // 下面的 形状 大小 indicatorPadding: EdgeInsets.all(5), // indicatorSize: TabBarIndicatorSize.label, // 和文字 的长度 // 可在 里面 配置 属性 indicator: BoxDecoration( color: Colors.blue, borderRadius: BorderRadius.circular(10), ), // 背景 颜色 labelColor: Colors.yellow, // 这个 改变 文字 颜色 labelStyle: TextStyle(fontSize: 14), unselectedLabelStyle: TextStyle(fontSize: 12), unselectedLabelColor: Colors.white, // 未选中 的颜色 tabs: [ Tab( child: Text("fllowing"), ), Tab( child: Text("hot"), ), Tab( child: Text("video"), ), Tab( child: Text("video"), ), ], ), ), body: TabBarView( controller: _tabController, children: [ // 有顺序 ListView( children: [ ListTile( title: Text('i am fllowing list'), ), ], ), ListView( children: [ ListTile( title: Text('i am hot list'), ), ], ), ListView( children: [ ListTile( title: Text('i am video list'), ), ], ), ListView( children: [ ListTile( title: Text('i am video list'), ), ], ), ], ), ); } }
顶部导航
修改home.dart 代码 即可
import 'package:flutter/material.dart'; class HomePage extends StatefulWidget { const HomePage({Key? key}) : super(key: key); @override State<HomePage> createState() => _HomePageState(); } class _HomePageState extends State<HomePage> with SingleTickerProviderStateMixin { late TabController _tabController; @override void initState() { super.initState(); _tabController = TabController(length: 5, vsync: this); } @override Widget build(BuildContext context) { return Scaffold( appBar: PreferredSize( preferredSize: Size.fromHeight(40), child: AppBar( // 改变 阴影 elevation: 2, backgroundColor: Colors.white, centerTitle: true, // 不设置 头文字 直接 将 title 设置 为 tab title: SizedBox( // 改变 的 为 tabBar 的高度0 height: 30, child: TabBar( labelStyle: TextStyle( fontSize: 14 ), labelColor: Colors.red, indicatorWeight: 2, indicatorColor: Colors.red, indicatorSize: TabBarIndicatorSize.label, unselectedLabelColor: Colors.black, controller: _tabController, tabs: const[ Tab( child: Text("following"), ), Tab( child: Text("hot"), ), Tab( child: Text("video"), ), Tab( child: Text("basketball"), ), Tab( child: Text("other"), ), ], ), ), )), body: TabBarView( controller: _tabController, children: [ Text("fllowing"), Text("hot"), Text("video"), Text("basketball"), Text("other"), ], )); } }
TabBar结合Tab
通过material 来 修改tab Bar 背景颜色
BottomAppBar buildBottomAppBar() { return BottomAppBar( child: Theme( data: ThemeData( highlightColor: Colors.blueGrey[600], splashColor: Colors.grey, ), child: Material( color: Colors.grey[300], child: TabBar( labelColor: Colors.blue, controller: _tabController, tabs: [ Tab(text: "home",icon: Icon(Icons.home),), Tab(text: "category",icon: Icon(Icons.category),), Tab(text: "setting",icon: Icon(Icons.settings),), ], ), ), ), ); }
侧边栏的使用
简单使用
import 'package:flutter/material.dart'; class Example01 extends StatefulWidget{ const Example01({super.key}); @override State<StatefulWidget> createState() { return _ExampleState(); } } class _ExampleState extends State<Example01>{ @override Widget build(BuildContext context) { // Scaffold 用来 搭建主体结构 return Scaffold( drawer: buildDrawer(), endDrawer: buildDrawer(), appBar: AppBar(title: Text('title'), ), body: Center( // child: Text('i am the body') , child: Column( children: [ Builder(builder: (context){ return ElevatedButton(onPressed: (){ ScaffoldState state = context.findAncestorStateOfType<ScaffoldState>()!; state.openDrawer(); }, child: const Text('click me '),); }) ], ), ), ); } // 封装方法来构建 widget Container buildDrawer(){ return Container( color: Colors.white, width: 200, // column 可以让子 widget 在垂直方法显示排列 child: Column( children:<Widget> [ Container( color:Colors.blue,height: 200, child: Text('this is a text1'), ), Container( color: Colors.red,height: 200, child: Text('this is text2'), ) ], ), ); } } void main(){ runApp(MaterialApp( title: 'hello', home: Example01(), )); }
实现页面
// endDrawer: Drawer() // Drawer drawer: Drawer( child: Column( children: [ Row(children: [ Expanded( flex: 1, // 铺满 child: DrawerHeader( // 头的框架 decoration: BoxDecoration( color: Colors.yellow, image: DecorationImage ( // 修饰 图片 image: AssetImage("imgs/laying.jpg"), fit: BoxFit.cover, ), ), child: Column( children: [ ListTile( leading: CircleAvatar( backgroundImage: AssetImage("imgs/noodle.jpg"), ), title: Text( "youren", style: TextStyle(color: Color.fromRGBO(1, 1, 1, 1)), ), ), ListTile( title: Text("emial:253215@qq.com"), ) ], ), ), ) ]), ListTile( leading: Icon(Icons.people), title: Text("User"), ), Divider(), ListTile( leading: Icon(Icons.settings), title: Text("Setting"), ), ], ), ),
整合
import 'package:flutter/material.dart'; import '../pages/home.dart'; import '../pages/category.dart'; import '../pages/setting.dart'; class MyTest extends StatefulWidget { const MyTest({Key? key}) : super(key: key); @override State<MyTest> createState() => _MyTestState(); } class _MyTestState extends State<MyTest> with SingleTickerProviderStateMixin { // 当前页面 的下标 int _currentIndex = 0; // 有的页面 存入 到 一个list 里面 final List<Widget> _pages = const [ HomePage(), CategoryPage(), SettingPage(), ]; @override Widget build(BuildContext context) { return Scaffold( appBar: PreferredSize( preferredSize: Size.fromHeight(70), child: AppBar( actions: [ // 从左往右 IconButton( onPressed: () { print("search icon"); }, icon: Icon(Icons.search)), SizedBox(width: 100), IconButton( onPressed: () { print("more icon"); }, icon: Icon(Icons.more_horiz)), ], title: Text("底部导航栏的测试"), ), ), body: _pages[_currentIndex], bottomNavigationBar: BottomNavigationBar( // 如果 底部 按钮 四个或以上 需要使用到 type: BottomNavigationBarType.fixed, iconSize: 40, currentIndex: _currentIndex, onTap: (index) { setState(() { _currentIndex = index; }); }, items: [ BottomNavigationBarItem(icon: Icon(Icons.home), label: "首页"), BottomNavigationBarItem(icon: Icon(Icons.category), label: "分类"), BottomNavigationBarItem(icon: Icon(Icons.settings), label: "设置"), ], ), drawer: Drawer( child: Column( children: [ Row(children: [ Expanded( flex: 1, // 铺满 child: DrawerHeader( // 头的框架 decoration: BoxDecoration( image: DecorationImage( // 修饰 图片 image: AssetImage("imgs/laying.jpg"), fit: BoxFit.cover, ), ), child: Column( children: [ ListTile( leading: CircleAvatar( backgroundImage: AssetImage("imgs/noodle.jpg"), ), title: Text( "youren", style: TextStyle(color: Color.fromRGBO(1, 1, 1, 1)), ), ), ListTile( title: Text("emial:253215@qq.com"), ) ], ), ), ) ]), ListTile( leading: Icon(Icons.people), title: Text("User"), ), Divider(), ListTile( leading: Icon(Icons.settings), title: Text("Setting"), ), ], ), ), ); } } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, initialRoute: "/", routes: { "/": (context) => MyTest(), "setting": (context) => SettingPage(), }, ); } } void main() { runApp(const MyApp()); }
import 'package:flutter/material.dart'; class HomePage extends StatefulWidget { const HomePage({Key? key}) : super(key: key); @override State<HomePage> createState() => _HomePageState(); } class _HomePageState extends State<HomePage> with SingleTickerProviderStateMixin { late TabController _tabController; @override initState() { super.initState(); _tabController = TabController(length: 4, vsync: this); } @override Widget build(BuildContext context) { return Scaffold( appBar: PreferredSize( preferredSize: Size.fromHeight(50), child: AppBar( backgroundColor: Colors.white, title: SizedBox( height: 30, child: TabBar( labelColor: Colors.red, indicatorSize: TabBarIndicatorSize.label, indicatorColor: Colors.red, indicatorWeight: 2, unselectedLabelColor: Colors.black, controller: _tabController, labelStyle: TextStyle(fontSize: 15), tabs: [ Tab( child: Text("fllowing"), ), Tab( child: Text("hot"), ), Tab( child: Text("video"), ), Tab( child: Text("basketball"), ), ], ), ), ), ), body: TabBarView( controller: _tabController, children: [ TextButton( onPressed: () { Navigator.of(context).pushNamed("setting"); }, style: ButtonStyle( backgroundColor: MaterialStateProperty.all(Colors.white), fixedSize: MaterialStateProperty.all<Size>( Size(200, 50)), // 设置按钮的宽度为200,高度为50 ), child: Text("click me")), Text("hot"), Text("video"), Text("basketball"), ], )); } }