Flutter - 底部导航详解与案例示范

简介: Flutter - 底部导航详解与案例示范

Flutter - 底部导航栏解析与示范


1. BottomNavigationBar 详解

显示在应用程序底部的 material Widget,用于在少量视图中进行选择,通常在 3 - 5 个之间。底部导航栏由文本标签、图标或两者形式的多个项目组成,布置在一块 material 的顶部。它在应用程序的顶级视图之间提供快速导航。对于更大的屏幕比如10.6存及以上大小的平板,侧边导航比底部导航栏可能更合适。底部导航栏通常与Scaffold一起使用,它作为Scaffold.bottomNavigationBar参数提供。

底部导航栏的类型会更改其项目的显示方式。如果未指定,则在少于 4 个项目时,自动设置为BottomNavigationBarType.fixed,否则设置为BottomNavigationBarType.shifting

项目的长度必须至少为两个,并且每个项目的图标和标题/标签不得为空。

1.1 BottomNavigationBar 类的构造函数

BottomNavigationBar({
  Key? key, // Widget、Element 和 SemanticsNode 的标识符。 
  required List<BottomNavigationBarItem> items, // 带有图标和标题的按钮的列表,见 1.2 节
  ValueChanged<int>? onTap,
  int currentIndex = 0, // 当前活动的BottomNavigationBarItem 的项目索引。
  double? elevation, // 用于定义该 BottomNavigationBar 相对于其父级的`z`轴坐标,如果为 null,则默认为8.0。
  BottomNavigationBarType? type, // 定义 BottomNavigationBar 的布局和行为。见 1.3 节
  Color? fixedColor, // 颜色,为ARGB 格式的不可变 32 位颜色值。
  Color? backgroundColor, // 背景填充色,为ARGB 格式的不可变 32 位颜色值。
  double iconSize = 24.0, // 所有 BottomNavigationBarItem 图标的大小。[...]
  Color? selectedItemColor, // 选定的 BottomNavigationBarItem.icon 和 BottomNavigationBarItem.title 的颜色。[...]
  Color? unselectedItemColor,
  IconThemeData? selectedIconTheme, // 当前选中的BottomNavigationBarItem.icon 中图标的大小、不透明度和颜色 。[...]
  IconThemeData? unselectedIconTheme, // 当前未选中的BottomNavigationBarItem.icon 中图标的大小、不透明度和颜色 。[...]
  double selectedFontSize = 14.0, // BottomNavigationBarItem标签被选中时 的字体大小。[...]
  double unselectedFontSize = 12.0,
  TextStyle? selectedLabelStyle,
  TextStyle? unselectedLabelStyle, // 未选中时 ,BottomNavigationBarItem标签 的TextStyle 。
  bool? showSelectedLabels, // 是否为选定的BottomNavigationBarItem显示标签。
  bool? showUnselectedLabels, // 是否为未选中的BottomNavigationBarItem显示标签。
  MouseCursor? mouseCursor,
  bool? enableFeedback,
  BottomNavigationBarLandscapeLayout? landscapeLayout
})
其中:

创建底部导航栏,通常用作 ScaffoldScaffold.bottomNavigationBar 参数。items 的长度必须至少为两个,并且每个项目的图标和标签不能为空。

  • 如果 type为 null ,则当有两个或三个item时使用BottomNavigationBarType.fixed ,否则使用BottomNavigationBarType.shifting
  • iconSize 、selectedFontSize、unselectedFontSize和 elevation 参数必须为非空且非负数。
  • 如果selectedLabelStyle.colorunselectedLabelStyle.color 值为非空,将使用它们来代替selectedItemColorunselectedItemColor
  • 如果使用自定义IconThemeDatas,您必须同时提供 selectedIconThemeunselectedIconTheme ,并且必须同时设置 IconThemeData.color IconThemeData.size
  • 如果同时设置了selectedLabelStyle.fontSizeselectedFontSize,将使用 selectedLabelStyle.fontSize
  • 只能指定selectedItemColor和fixedColor之一。前者是首选,fixedColor的存在只是为了向后兼容。
  • 如果showSelectedLabelsnull,则使用bottonnavigationbarthemedata.showselectedlables。如果bottonnavigationbarthemdata.showSelectedLabelsnull,则showSelectedLabels默认为true
  • 如果showUnselectedLabels为空,则使用bottonnavigationbarthemedata.showunselectedlables。如果bottonnavigationbarthedata.showselectedlabels为空,则当类型为BottomNavigationBarType.fixed时,showUnselectedLabels默认为true,当类型为BottomNavigationBarType.shifting时,showUnselectedLabels默认为false

1.2 关于BottomNavigationBarItem 类 (items 列表 成员的类型)

这个类很少单独使用。它通常嵌入在上面的底部导航小部件之一中。它一般是 material 的 BottomNavigationBar 或带有图标和标题 的 iOS 主题 CupertinoTabBar 中的交互式按钮。

其构造函数:

const BottomNavigationBarItem({
  required Widget icon,
  @Deprecated('Use "label" instead, as it allows for an improved text-scaling experience. ' 'This feature was deprecated after v1.19.0.') Widget? title,
  String? label,
  Widget? activeIcon,
  Color? backgroundColor,
  String? tooltip
})

1.2.1 属性

名称 描述1 描述2 描述3
activeIcon Widget final 选择此底部导航项时显示的替代图标。[…]
backgroundColor Color? final material BottomNavigationBar 的背景径向动画的颜色。[…]
hashCode int read-only, inherited 此对象的哈希码。[…]
icon Widget final 项目的图标。[…]
label String? final BottomNavigationBarItem 的文本标签。[…]
runtimeType Type read-only, inherited 对象的运行时类型的表示。
title Widget? final 项目的标题。如果未提供标题,则只有在 Material Design BottomNavigationBar中未使用时才会显示该图标。[…]
@Deprecated (‘使用 “label” 代替,因为它可以改善文本缩放体验。’ ‘此功能在 v1.19.0 之后被弃用。’)
rtooltip String? final 当用户长按该项目时 ,此 BottomNavigationBarItem的工具提示中显示的文本。[…]

1.2.2 方法

1. (inherited) noSuchMethod()
noSuchMethod(Invocation invocation) → dynamic

在访问不存在的方法或属性时调用。[…]

2. (inherited) toString()
toString() → String

此对象的字符串表示形式。[…]

1.2.3 运算符

1. (inherited) ==
operator ==(Object other) → bool

相等运算符。[…]

1.3 BottomNavigationBarType 枚举

常量

1. fixed
fixed → const BottomNavigationBarType

底部导航栏的底部导航栏具有固定宽度。如果固定则主要是体现在当点击某个导航按钮时,被点击的按钮不会移动也不会改变大小。

const BottomNavigationBarType(0)

2. shifting
shifting → const BottomNavigationBarType

底部导航栏底部导航栏的位置和大小会产生动画,当轻击标签时,标签会淡入。

const BottomNavigationBarType(1)

3. values
values → const List<BottomNavigationBarType>

此枚举中值的常量列表,按其声明顺序排列。

2. BottomNavigationBar 示范项目

2.1 项目结构

2.2 代码

项目入口:main.dart

import 'package:flutter/material.dart';
import 'tabsPage/index.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        // title: 'Flutter Demo',
        theme: ThemeData(
          // This is the theme of your application.
          primarySwatch: Colors.orange,
        ),
        home: const Tabs());
  }
}

底部导航控制:tabsPage/index.dart

import 'package:flutter/material.dart';
import 'Page1.dart';
import 'Page2.dart';
import 'Page3.dart';
import 'Page4.dart';
class Tabs extends StatefulWidget {
  const Tabs({Key? key}) : super(key: key);
  @override
  _TabsState createState() => _TabsState();
}
class _TabsState extends State<Tabs> {
  int _selectedIndex = 0; // 用作被选中的 Tab 的索引号
  final List _tabPages = [
    const Page1(),
    const Page2(),
    const Page3(),
    const Page4()
  ]; // 列举所有 Tab 控制切换将用到的页面
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _tabPages[_selectedIndex],
      bottomNavigationBar: BottomNavigationBar(
        selectedFontSize: 12.0, // 被选中时的字体大小
        unselectedFontSize: 14.0, // 未被选中时的字体大小
        showSelectedLabels: true, // 被选中时是否显示Label
        showUnselectedLabels: true, // 未被选中时是否显示Label
        enableFeedback: true, //点击会产生咔嗒声,长按会产生短暂的振动
        selectedItemColor: Colors.orange, // 设置被选中时的图标颜色
        unselectedItemColor: Colors.grey, // 设置未被选中时的图标颜色
        items: const <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: Icon(
              Icons.home,
              size: 24.0,
            ),
            label: '工作室',
            backgroundColor: Colors.white,
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.event_note, size: 24.0),
            label: '数据',
            backgroundColor: Colors.white,
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.account_box_outlined, size: 24.0),
            label: '通讯录',
            backgroundColor: Colors.white,
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.person, size: 24.0),
            label: '我的',
            backgroundColor: Colors.white,
          ),
        ],
        // 设置当前(即被选中时)页面
        currentIndex: _selectedIndex,
        // 当点击其中一个[items]被触发
        onTap: (int index) {
          setState(() {
            /*
             * item 被点中时更改当前索引。
             * 其中,currentIndex 字段设置的值时响应式的
             * 新版dart不用this.
             */
            _selectedIndex = index;
          });
        },
      ),
    );
  }
}

底部导航得具体页面:

page1

import 'package:flutter/material.dart';
enum WhyFarther { harder, smarter, selfStarter, tradingCharter }
class Page1 extends StatefulWidget {
  const Page1({Key? key}) : super(key: key);
  @override
  _Page1State createState() => _Page1State();
}
class _Page1State extends State<Page1> {
  set _selection(WhyFarther _selection) {}
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("JcStdio"), actions: <Widget>[
        IconButton(
          icon: const Icon(Icons.search),
          onPressed: () {},
        ),
        PopupMenuButton<WhyFarther>(
          onSelected: (WhyFarther result) {
            setState(() {
              _selection = result;
            });
          },
          icon: const Icon(
            Icons.add_circle_outline,
            size: 24.0,
          ),
          itemBuilder: (BuildContext context) => <PopupMenuEntry<WhyFarther>>[
            PopupMenuItem<WhyFarther>(
                value: WhyFarther.selfStarter,
                child: Row(
                  children: const [
                    Icon(
                      Icons.qr_code_scanner_outlined,
                      size: 24.0,
                    ),
                    Text('扫一扫')
                  ],
                )),
            PopupMenuItem<WhyFarther>(
                value: WhyFarther.tradingCharter,
                child: Row(
                  children: const [
                    Icon(
                      Icons.person_add,
                      size: 24.0,
                    ),
                    Text('添加朋友')
                  ],
                )),
          ],
        )
      ]),
      body: const Text('这里是 jcstdio: jclee95的个人工作室,欢迎你的到来!'),
    );
  }
}

page2

import 'package:flutter/material.dart';
class Page2 extends StatefulWidget {
  const Page2({Key? key}) : super(key: key);
  @override
  _Page2State createState() => _Page2State();
}
class _Page2State extends State<Page2> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("数据")),
      body: const Text('欢迎浏览数据中心页...'),
    );
  }
}

page3

import 'package:flutter/material.dart';
import '/datas/listData.dart';
// import '/datas/usercard.dart';
class Page3 extends StatefulWidget {
  const Page3({Key? key}) : super(key: key);
  @override
  _Page3State createState() => _Page3State();
}
class _Page3State extends State<Page3> {
  List<Widget> _listData() {
    var tempList = listData.map((value) {
      return ListTile(
          leading: Image.network(value["imageurl"]),
          title: Text(value["title"]),
          subtitle: Text(value["author"]));
    });
    return tempList.toList();
  }
// UserCard
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text("通讯录"),
        ),
        body: ListView(
          children: _listData(),
        ));
  }
}

page4

import 'package:flutter/material.dart';
class Page4 extends StatefulWidget {
  const Page4({Key? key}) : super(key: key);
  @override
  _Page3State createState() => _Page3State();
}
class _Page3State extends State<Page4> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text("我的"),
        ),
        body: const Text('欢迎来到个人中心!'));
  }
}

3. 项目效果

3.1 page1

3.2 page2

3.3 page3

3.4. page4

目录
相关文章
|
10天前
|
Dart UED 开发者
flutter鸿蒙版本通过底部导航栏的实现熟悉架构及语法
这篇博客详细解析了一个 Flutter 应用的完整代码,实现了带有底部导航栏的功能,允许用户在不同页面之间切换。通过逐行讲解,帮助读者理解 Flutter 的结构、状态管理和组件交互。代码涵盖了从引入包、创建主入口、定义无状态和有状态组件,到构建用户界面的全过程。希望对 Flutter 开发者有所帮助。
143 3
|
1月前
|
Dart UED 索引
flutter鸿蒙版本通过底部导航栏的实现熟悉架构及语法
flutter鸿蒙版本通过底部导航栏的实现熟悉架构及语法
20 2
|
6月前
|
图形学
Flutter笔记:Matrix4矩阵变换与案例
Flutter笔记:Matrix4矩阵变换与案例
426 0
|
6月前
Flutter笔记:使用Flutter构建响应式PC客户端/Web页面-案例
Flutter笔记:使用Flutter构建响应式PC客户端/Web页面-案例
318 0
Flutter 底部导航栏BottomNavigationBar,并关联PageView实现滑动切换
Flutter 底部导航栏BottomNavigationBar,并关联PageView实现滑动切换
350 0
|
索引
【Flutter】底部导航栏页面框架 ( BottomNavigationBar 底部导航栏 | PageView 滑动页面 | 底部导航与滑动页面关联操作 )(一)
【Flutter】底部导航栏页面框架 ( BottomNavigationBar 底部导航栏 | PageView 滑动页面 | 底部导航与滑动页面关联操作 )(一)
348 0
|
Web App开发 前端开发 API
【新年快乐第三弹】在 Flutter 中创建漂亮的底部导航栏
ConvexBottomBar是一个底部导航栏组件,用于展现凸起的TAB效果,支持多种内置样式与动画交互。你可以在appbar.codemagic.app上找到在线样例。
515 0
|
Dart 开发者
【Flutter】底部导航栏页面框架 ( BottomNavigationBar 底部导航栏 | PageView 滑动页面 | 底部导航与滑动页面关联操作 )(二)
【Flutter】底部导航栏页面框架 ( BottomNavigationBar 底部导航栏 | PageView 滑动页面 | 底部导航与滑动页面关联操作 )(二)
154 0
【Flutter】底部导航栏页面框架 ( BottomNavigationBar 底部导航栏 | PageView 滑动页面 | 底部导航与滑动页面关联操作 )(二)
|
Dart 开发者
【Flutter】底部导航栏实现 ( BottomNavigationBar 底部导航栏 | BottomNavigationBarItem 导航栏条目 | PageView )(二)
【Flutter】底部导航栏实现 ( BottomNavigationBar 底部导航栏 | BottomNavigationBarItem 导航栏条目 | PageView )(二)
340 0
【Flutter】底部导航栏实现 ( BottomNavigationBar 底部导航栏 | BottomNavigationBarItem 导航栏条目 | PageView )(二)
|
移动开发 Dart 前端开发
【Flutter】初探之开发小结 | 参考教程 | 参考案例 | 遇到的问题
【Flutter】初探之开发小结 | 参考教程 | 参考案例 | 遇到的问题
152 0