在 Flutter 中使用 NavigationRail 和 BottomNavigationBar

本文将向您展示如何使用NavigationRail和BottomNavigationBar在 Flutter 中创建自适应布局。我们将浏览一下这个概念,然后通过一个完整的例子来在实践中应用这个概念。

NavigationRail小部件用于创建位于应用左侧或右侧的"垂直标签栏"。它非常适合平板电脑、笔记本电脑、电视等宽屏设备。它通常包含多个视图,让用户可以轻松地在不同视图之间切换。

BottomNavigationBar小部件用于创建非常适合智能手机的底部标签栏。它由多个选项卡组成,让用户可以轻松地在视图之间导航。

我们可以使用NavigationRail和BottomNavigationBar来构建现代自适应布局。当屏幕很大时,我们显示NavigationRail,当屏幕较小时,我们显示BottomNavigationBar。一次只出现其中一个。要检测屏幕宽度,我们可以使用:

dart 复制代码
MediaQuery.of(context).size.width

复制

例子

应用预览

我们要构建的应用程序有一个导航栏、一个底部标签栏和 4 个不同的视图:主页、Feed、收藏夹和设置。每个视图都与底部标签栏的一个标签和导航栏的一个项目相连。

如果屏幕宽度小于 640 像素,则将呈现底部标签栏,而不会显示左侧导航栏。

如果屏幕宽度等于或大于 640 像素,则不会呈现底部标签栏,而会显示左侧导航栏。

以下是它的工作原理:

截图

chip

代码

这是生成上述应用程序的完整代码(带有解释):

dart 复制代码
// main.dart
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        // Remove the debug banner
        debugShowCheckedModeBanner: false,
        title: '大前端之旅',
        theme: ThemeData(primarySwatch: Colors.indigo),
        home: const HomeScreen());
  }
}

class HomeScreen extends StatefulWidget {
  const HomeScreen({Key? key}) : super(key: key);

  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  // The contents of views
  // Only the content associated with the selected tab is displayed on the screen
  final List<Widget> _mainContents = [
    // Content for Home tab
    Container(
      color: Colors.yellow.shade100,
      alignment: Alignment.center,
      child: const Text(
        'Home',
        style: TextStyle(fontSize: 40),
      ),
    ),
    // Content for Feed tab
    Container(
      color: Colors.purple.shade100,
      alignment: Alignment.center,
      child: const Text(
        'Feed',
        style: TextStyle(fontSize: 40),
      ),
    ),
    // Content for Favorites tab
    Container(
      color: Colors.red.shade100,
      alignment: Alignment.center,
      child: const Text(
        'Favorites',
        style: TextStyle(fontSize: 40),
      ),
    ),
    // Content for Settings tab
    Container(
      color: Colors.pink.shade300,
      alignment: Alignment.center,
      child: const Text(
        'Settings',
        style: TextStyle(fontSize: 40),
      ),
    )
  ];

  // The index of the selected tab
  // In the beginning, the Home tab is selected
  int _selectedIndex = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('大前端之旅'),
      ),
      // Show the bottom tab bar if screen width < 640
      bottomNavigationBar: MediaQuery.of(context).size.width < 640
          ? BottomNavigationBar(
              currentIndex: _selectedIndex,
              unselectedItemColor: Colors.grey,
              selectedItemColor: Colors.indigoAccent,
              // called when one tab is selected
              onTap: (int index) {
                setState(() {
                  _selectedIndex = index;
                });
              },
              // bottom tab items
              items: const [
                  BottomNavigationBarItem(
                      icon: Icon(Icons.home), label: 'Home'),
                  BottomNavigationBarItem(
                      icon: Icon(Icons.feed), label: 'Feed'),
                  BottomNavigationBarItem(
                      icon: Icon(Icons.favorite), label: 'Favorites'),
                  BottomNavigationBarItem(
                      icon: Icon(Icons.settings), label: 'Settings')
                ])
          : null,
      body: Row(
        mainAxisSize: MainAxisSize.max,
        children: [
          // Show the navigaiton rail if screen width >= 640
          if (MediaQuery.of(context).size.width >= 640)
            NavigationRail(
              minWidth: 55.0,
              selectedIndex: _selectedIndex,
              // Called when one tab is selected
              onDestinationSelected: (int index) {
                setState(() {
                  _selectedIndex = index;
                });
              },
              labelType: NavigationRailLabelType.all,
              selectedLabelTextStyle: const TextStyle(
                color: Colors.amber,
              ),
              leading: Column(
                children: const [
                  SizedBox(
                    height: 8,
                  ),
                  CircleAvatar(
                    radius: 20,
                    child: Icon(Icons.person),
                  ),
                ],
              ),
              unselectedLabelTextStyle: const TextStyle(),
              // navigation rail items
              destinations: const [
                NavigationRailDestination(
                    icon: Icon(Icons.home), label: Text('Home')),
                NavigationRailDestination(
                    icon: Icon(Icons.feed), label: Text('Feed')),
                NavigationRailDestination(
                    icon: Icon(Icons.favorite), label: Text('Favorites')),
                NavigationRailDestination(
                    icon: Icon(Icons.settings), label: Text('Settings')),
              ],
            ),

          // Main content
          // This part is always shown
          // You will see it on both small and wide screen
          Expanded(child: _mainContents[_selectedIndex]),
        ],
      ),
    );
  }
}

复制

构造函数和引用

NavigationRail 构造函数:

dart 复制代码
NavigationRail({
  Key? key, 
  Color? backgroundColor, 
  bool extended = false, 
  Widget? leading, 
  Widget? trailing, 
  required List<NavigationRailDestination> destinations, 
  required int selectedIndex, 
  ValueChanged<int>? onDestinationSelected, 
  double? elevation, 
  double? groupAlignment, 
  NavigationRailLabelType? labelType, 
  TextStyle? unselectedLabelTextStyle, 
  TextStyle? selectedLabelTextStyle, 
  IconThemeData? unselectedIconTheme, 
  IconThemeData? selectedIconTheme, 
  double? minWidth, 
  double? minExtendedWidth, 
  bool? useIndicator, 
  Color? indicatorColor
})

复制

BottomNavigationBar 构造函数:

dart 复制代码
BottomNavigationBar({
  Key? key, 
  required List<BottomNavigationBarItem> items, 
  ValueChanged<int>? onTap, 
  int currentIndex = 0, 
  double? elevation, 
  BottomNavigationBarType? type, 
  Color? fixedColor, 
  Color? backgroundColor, 
  double iconSize = 24.0, 
  Color? selectedItemColor, 
  Color? unselectedItemColor, 
  IconThemeData? selectedIconTheme, 
  IconThemeData? unselectedIconTheme, 
  double selectedFontSize = 14.0, 
  double unselectedFontSize = 12.0, 
  TextStyle? selectedLabelStyle, 
  TextStyle? unselectedLabelStyle, 
  bool? showSelectedLabels, 
  bool? showUnselectedLabels, 
  MouseCursor? mouseCursor, 
  bool? enableFeedback, 
  BottomNavigationBarLandscapeLayout? landscapeLayout
})

复制

参考:

navigation:设计(material.io

NavigationRail 类(flutter.dev)

NavigationRailDestination类 (flutter.dev)

BottomNavigationBar 类(flutter.dev)

后记

您已经学习了一种使用 NavigationRail 和 BottomNavigationBar 创建现代自适应用户界面的简单但有效的技术。考虑到这些知识,您可以为从智能手机到平板电脑和笔记本电脑的各种设备构建更直观、更有吸引力的应用程序。因此,您的应用程序将获得越来越多的用户,并有更大的成功机会。

https://cloud.tencent.com/developer/article/1968638

相关推荐
恋猫de小郭7 分钟前
Android 将强制应用使用主题图标,你怎么看?
android·前端·flutter
玲珑Felone1 小时前
从flutter源码看其渲染机制
android·flutter
ALLIN21 小时前
Flutter 三种方式实现页面切换后保持原页面状态
flutter
Dabei21 小时前
Flutter 国际化
flutter
Dabei21 小时前
Flutter MQTT 通信文档
flutter
Dabei1 天前
Flutter 中实现 TCP 通信
flutter
孤鸿玉1 天前
ios flutter_echarts 不在当前屏幕 白屏修复
flutter
前端 贾公子1 天前
《Vuejs设计与实现》第 16 章(解析器) 上
vue.js·flutter·ios
tangweiguo030519871 天前
Flutter 数据存储的四种核心方式 · 从 SharedPreferences 到 SQLite:Flutter 数据持久化终极整理
flutter
0wioiw01 天前
Flutter基础(②④事件回调与交互处理)
flutter