0


Flutter 项目实战 底部导航 六

/ 生活中常部分app底部导航样式 /

  1. 从智能手机的普及我们的生活 , 手机已经为我们生活提供了方便 . 购买手机后系统默认安装了很多款app , 随便点开一款手机app 进入应用首页映入眼帘的就是底部导航 . 可以说手机app为我们生活提供了方便 , 同时app里面的底部导航为我们更好的使用应用 . 市面上的app底部导航切换样式都差不多 (分底部Tab 导航栏 舵式导航栏) . 点击底部导航选项可以切换到不同功能模块的 , 让用户在使用的时候更加清楚要导航的功能 .


底部Tab(今日头条&微信&美团&网易云音乐)


舵式导航栏(微博&闲鱼)

/ app底部导航构造 /

导航选项纯图标

导航纯文本

** 导航图文混排**

/ Flutter 实现底部导航 /

BottomNavigationBarItem

服务于 BottomNavigationBar . 包括属性icon (选项图标)、title (选项包括文本的widget被弃用)、label (导航栏文本值)、backgroundColor、tooltip (长按时选项顶部弹出提示 , 长按选项时选项样式不会发生改变)

在flutter sdk 大于1.19.0的版本上使用该参数 , 抛出如下异常 :

backgroundColor 选项有渐变和移动效果状态下的背景颜色

BottomNavigationBar 参数 BottomNavigationBarType 是 BottomNavigationBarType.shifting 生效. 会覆盖导航栏BottomNavigationBar背景颜色 . 访问B站查看效果

tooltip 长按选项弹出提示 访问B站查看效果

BottomNavigationBar

底部导航 可以自定义 选项文本、图标样式 . 长按点击弹出提示 . 可以使用flutter自带的icon 切换图标的样式 .

items / BottomNavigationBarItem 集合

flutter自带的Icon

  1. class StartPage extends StatefulWidget {
  2. StartPage({Key? key, this.title}) : super(key: key);
  3. final String? title;
  4. @override
  5. _StartPageState createState() => _StartPageState();
  6. }
  7. class _StartPageState extends State<StartPage> {
  8. GlobalKey<StackWState> _stackGk = GlobalKey<StackWState>();
  9. @override
  10. Widget build(BuildContext context) {
  11. return Scaffold(
  12. bottomNavigationBar: BotNavBar(
  13. stackValue: (int currentIndex, List<int> tabInt) {
  14. _stackGk.currentState!.changeStack(currentIndex, tabInt);
  15. },
  16. ),
  17. body: StackWidget(
  18. key: _stackGk,
  19. ));
  20. }
  21. }
  1. import 'package:flutter/cupertino.dart';
  2. import 'package:flutter_bottom_navigator/base/presenter/IPresenter.dart';
  3. import 'package:flutter_bottom_navigator/base/view/BaseView.dart';
  4. import 'package:flutter_bottom_navigator/base/view/IView.dart';
  5. class StackWidget extends BaseView {
  6. final int? currentIndex;
  7. final List<int>? tabInt;
  8. StackWidget({this.currentIndex, this.tabInt, Key? key}) : super(key: key);
  9. @override
  10. BaseViewState<IPresenter<IView>, BaseView> getState() {
  11. return StackWState();
  12. }
  13. }
  14. class StackWState extends BaseViewState<IPresenter, StackWidget> {
  15. int _currentIndex = 0;
  16. List<int>? _tabInt;
  17. final List<Widget> _children = [
  18. Center(
  19. child: Text('Page1'),
  20. ),
  21. Center(
  22. child: Text('Page2'),
  23. ),
  24. ];
  25. @override
  26. void initState() {
  27. // TODO: implement initState
  28. super.initState();
  29. _tabInt = widget.tabInt == null ? [0] : widget.tabInt;
  30. }
  31. void changeStack(int currentIndex, List<int> tabInt) {
  32. setState(() {});
  33. _currentIndex = currentIndex;
  34. _tabInt = tabInt;
  35. }
  36. //Page的显示和隐藏
  37. _child(int _index) {
  38. return Offstage(
  39. offstage: !(_currentIndex == _index),
  40. child: _tabInt!.contains(_index) ? _children[_index] : Container(),
  41. );
  42. }
  43. @override
  44. buildWidget() {
  45. // TODO: implement buildWidget
  46. return Stack(
  47. children: <Widget>[
  48. _child(0),
  49. _child(1),
  50. ],
  51. );
  52. }
  53. }
  1. import 'package:flutter/material.dart';
  2. class BotNavBar extends StatefulWidget {
  3. final ValueChanged? stackValue;
  4. BotNavBar({Key? key, this.stackValue}) : super(key: key);
  5. @override
  6. _BotNavBarState createState() => _BotNavBarState();
  7. }
  8. class _BotNavBarState extends State<BotNavBar> {
  9. List<int> tabInt = [0];
  10. int _currentIndex = 0;
  11. late var _tabImages;
  12. @override
  13. void initState() {
  14. // TODO: implement initState
  15. super.initState();
  16. _tabImages = [
  17. _singleTabImage('home'),
  18. _singleTabImage('type'),
  19. _singleTabImage('mine'),
  20. ];
  21. }
  22. BottomNavigationBarItem _singleBotNavItem(_index) {
  23. return BottomNavigationBarItem(
  24. icon: _getTabIcon(
  25. _index,
  26. ),
  27. backgroundColor: Colors.red,
  28. tooltip: '$_index tooltips',
  29. //title: Text('$_index title'),
  30. label: '$_index label');
  31. }
  32. _singleTabImage(_labelPng) {
  33. return [
  34. Icon(Icons.message),
  35. Icon(Icons.message),
  36. ];
  37. }
  38. Widget _getTabIcon(int curIndex) {
  39. if (curIndex == _currentIndex) {
  40. return _tabImages[curIndex][0];
  41. }
  42. return _tabImages[curIndex][1];
  43. }
  44. @override
  45. Widget build(BuildContext context) {
  46. return BottomNavigationBar(
  47. type: BottomNavigationBarType.fixed,
  48. onTap: _onTabTapped,
  49. currentIndex: _currentIndex,
  50. backgroundColor: Colors.white,
  51. selectedItemColor: Colors.blue,
  52. unselectedItemColor: Color(0xffAFB1BD),
  53. elevation: 6.0,
  54. selectedIconTheme: IconThemeData(color: Colors.green),
  55. unselectedIconTheme: IconThemeData(color: Colors.red),
  56. selectedLabelStyle: TextStyle(inherit: true),
  57. //fixedColor: Colors.blue,
  58. showUnselectedLabels: true,
  59. showSelectedLabels: true,
  60. mouseCursor: SystemMouseCursors.move,
  61. enableFeedback: false,
  62. items: [
  63. _singleBotNavItem(0),
  64. _singleBotNavItem(1),
  65. ],
  66. );
  67. }
  68. _onTabTapped(int index) {
  69. setState(() {});
  70. _currentIndex = index;
  71. if (!tabInt.contains(index)) {
  72. tabInt.add(index);
  73. }
  74. if (widget.stackValue != null) {
  75. widget.stackValue!(_currentIndex, tabInt);
  76. }
  77. }
  78. }
  79. typedef ValueChanged = void Function(
  80. int currentIndex,
  81. List<int> tabInt,
  82. );

自定义Icon

创建assets 文件夹来存储要读取的自定义图标

在 pubspec.yaml 文件里面配置图片的依赖

  1. _singleTabImage(_labelPng) {
  2. return [
  3. Image.asset(
  4. 'assets/${_labelPng}_b_select.png',
  5. width: 40.0,
  6. height: 40.0,
  7. ),
  8. Image.asset(
  9. 'assets/${_labelPng}_b_normal.png',
  10. width: 40.0,
  11. height: 40.0,
  12. )
  13. ];
  14. }

elevation / 导航栏阴影Z坐标

selectedLabelStyle / unselectedLabelStyle

导航栏选中文本的样式 (字体颜色、背景颜色、字体权重、字体阴影 、…...)

导航栏选中文本的样式 (字体颜色、背景颜色、字体权重、字体阴影 、……)

showSelectedLabels / showUnselectedLabels

是否显示选中时的文本 / 是否显示未选中时的文本

GlobalKey 实现导航局部刷新

StartPage 包含了 内容区域 (StackWidget) 和底部导航 (BotNavBar) . 当首次进入应用时 , 会渲染内容容区域和底部导航 . 当我们需要切换其它导航时 , 要做到切换导航重新渲染内容区域和底部导航而不执行内容区域和底部导航的父控件StartPage的build函数,需要用到GlobalKey来实现点击导航刷新内容区域而不执行StartPage的build函数 .

  1. class _StartPageState extends State<StartPage> {
  2. GlobalKey<StackWState> _stackGk = GlobalKey<StackWState>();
  3. @override
  4. Widget build(BuildContext context) {
  5. print('StartPage _build');
  6. return Scaffold(
  7. bottomNavigationBar: BotNavBar(
  8. stackValue: (int currentIndex, List<int> tabInt) {
  9. _stackGk.currentState!.changeStack(currentIndex, tabInt);
  10. },
  11. ),
  12. body: StackWidget(
  13. key: _stackGk,
  14. ));
  15. }
  16. }

flutter_bottom_navigator 案例下载

标签: flutter

本文转载自: https://blog.csdn.net/u013491829/article/details/122271485
版权归原作者 xmiaoshen 所有, 如有侵权,请联系我们删除。

“Flutter 项目实战 底部导航 六”的评论:

还没有评论