【问题标题】:Navigation rail with flutter带颤振的导航轨道
【发布时间】:2020-08-22 09:07:52
【问题描述】:

材料设计指南包括一个名为 Navigation rail 的组件。

如何使用颤振创建导航栏?

【问题讨论】:

    标签: flutter material-design flutter-layout flutter-navigation


    【解决方案1】:

    NavigationRail

    • 一种材质小部件,旨在显示在应用的左侧或右侧,以便在少量视图之间导航,通常在三到五个之间。

    示例代码

    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(
          title: _title,
          debugShowCheckedModeBanner: false,
          home: HomeWidget(),
        );
      }
    }
    
    class HomeWidget extends StatefulWidget {
      HomeWidget({Key key}) : super(key: key);
    
      @override
      _HomeWidgetState createState() => _HomeWidgetState();
    }
    
    class _HomeWidgetState extends State<HomeWidget> {
      int _selectedIndex = 0;
      bool showNavigationBar = false;
    
      var list = [
        HomePage(),
        WalkPage(),
        LocationPage(),
        NotificationPage(),
        SettingsPage(),
        SearchPage()
      ];
    
      var title = [
        "HomePage",
        'WalkPage',
        'LocationPage',
        'NotificationPage',
        'SettingsPage',
        'SearchPage'
      ];
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(title[_selectedIndex]),
            centerTitle: false,
            leading: IconButton(
                icon: Icon(
                  Icons.menu,
                  color: Colors.white,
                ),
                onPressed: () {
                  setState(() {
                    showNavigationBar = !showNavigationBar;
                  });
                }),
          ),
          body: Container(
            child: SafeArea(
                child: Stack(
              children: <Widget>[
                list[_selectedIndex],
                Positioned(
                  top: 0,
                  left: 0,
                  child: Visibility(
                    visible: showNavigationBar,
                    child: Container(
                      height: MediaQuery.of(context).size.height,
                      child: NavigationRail(
                        selectedIndex: _selectedIndex,
                        elevation: 10,
                        backgroundColor: Colors.white,
                        leading: Container(
                          child: Center(child: Text('leading')),
                        ),
                        trailing: Container(
                          child: Center(child: Text('trailing')),
                        ),
                        selectedIconTheme: IconThemeData(color: Colors.purple, size: 30),
                        unselectedIconTheme: IconThemeData(color: Colors.grey, size: 20),
                        selectedLabelTextStyle:
                            TextStyle(color: Colors.purple, fontWeight: FontWeight.bold),
                        unselectedLabelTextStyle:
                            TextStyle(color: Colors.grey, fontWeight: FontWeight.normal),
                        onDestinationSelected: (int index) {
                          setState(() {
                            _selectedIndex = index;
                            showNavigationBar = !showNavigationBar;
                          });
                        },
                        labelType: NavigationRailLabelType.none,
                        destinations: [
                          NavigationRailDestination(
                            icon: Icon(Icons.home),
                            selectedIcon: Icon(Icons.home),
                            label: Text('Home'),
                          ),
                          NavigationRailDestination(
                            icon: Icon(Icons.directions_walk),
                            selectedIcon: Icon(Icons.directions_walk),
                            label: Text('Walk'),
                          ),
                          NavigationRailDestination(
                            icon: Icon(Icons.location_on),
                            selectedIcon: Icon(Icons.location_on),
                            label: Text('Location'),
                          ),
                          NavigationRailDestination(
                            icon: Icon(Icons.notifications),
                            selectedIcon: Icon(Icons.notifications),
                            label: Text('Notifications'),
                          ),
                          NavigationRailDestination(
                            icon: Icon(Icons.settings),
                            selectedIcon: Icon(Icons.settings),
                            label: Text('Settings'),
                          ),
                          NavigationRailDestination(
                            icon: Icon(Icons.search),
                            selectedIcon: Icon(Icons.search),
                            label: Text('Search'),
                          ),
                        ],
                      ),
                    ),
                  ),
                ),
              ],
            )),
          ),
        );
      }
    }
    
    class HomePage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Container(
          color: Colors.red,
          child: Center(
              child: Text('Home Page',
                  style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 20.0))),
        );
      }
    }
    
    class WalkPage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Container(
          color: Colors.blue,
          child: Center(
              child: Text('Walk Page',
                  style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 20.0))),
        );
      }
    }
    
    class LocationPage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Container(
          color: Colors.orange,
          child: Center(
              child: Text('Location Page',
                  style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 20.0))),
        );
      }
    }
    
    class NotificationPage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Container(
          color: Colors.green,
          child: Center(
              child: Text('Notification Page',
                  style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 20.0))),
        );
      }
    }
    
    class SettingsPage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Container(
          color: Colors.amber,
          child: Center(
              child: Text('Settings Page',
                  style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 20.0))),
        );
      }
    }
    
    class SearchPage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Container(
          color: Colors.teal,
          child: Center(
              child: Text('Search Page',
                  style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 20.0))),
        );
      }
    }
    

    让我们了解它的一些重要属性

    selectedIndex - 当前选定 NavigationRailDestination 的目的地索引。

    selectedIconTheme - 所选目的地中图标的视觉属性。

    unselectedIconTheme - 未选择目的地中图标的视觉属性。

    selectedLabelTextStyle - 选择目的地标签时的 TextStyle。

    unselectedLabelTextStyle - 目的地标签未选中时的 TextStyle。

    backgroundColor - 设置包含所有 NavigationRail 内容的容器的颜色。

    leading - 放置在目的地上方的导轨中的前导小部件

    trailing - 位于目标下方的轨道中的尾随小部件。

    labelType

    1. labelType: NavigationRailLabelType.all,
    2. labelType: NavigationRailLabelType.selected,
    3. labelType: NavigationRailLabelType.none,

    输出

    更多信息请阅读NavigationRail的文档

    您可以在NavigationRail demo 上测试现场演示

    【讨论】:

      【解决方案2】:

      最新版本的 Flutter 1.17 包含一个内置的 NavigationRail 组件。

      什么是导航栏?

      rail 是一个侧边导航组件,它显示三到七个应用程序目标,以及一个可选的浮动操作按钮。每个目的地都由一个图标和一个文本标签表示。导轨可以在更大的屏幕尺寸(例如台式机和平板电脑)上独立运行。当用户在屏幕尺寸和设备之间切换时,滑轨还可以补充其他导航组件,例如底部导航。

      示例

      import 'package:flutter/material.dart';
      
      void main() => runApp(MyApp());
      
      /// This Widget is the main application widget.
      class MyApp extends StatelessWidget {
        static const String _title = 'Flutter Code Sample';
      
        @override
        Widget build(BuildContext context) {
          return MaterialApp(
            title: _title,
            home: MyStatefulWidget(),
          );
        }
      }
      
      class MyStatefulWidget extends StatefulWidget {
        MyStatefulWidget({Key key}) : super(key: key);
      
        @override
        _MyStatefulWidgetState createState() => _MyStatefulWidgetState();
      }
      
      class _MyStatefulWidgetState extends State<MyStatefulWidget> {
        int _selectedIndex = 0;
      
        @override
        Widget build(BuildContext context) {
          return Scaffold(
            body: Row(
              children: <Widget>[
                NavigationRail(
                  selectedIndex: _selectedIndex,
                  onDestinationSelected: (int index) {
                    setState(() {
                      _selectedIndex = index;
                    });
                  },
                  labelType: NavigationRailLabelType.selected,
                  destinations: [
                    NavigationRailDestination(
                      icon: Icon(Icons.favorite_border),
                      selectedIcon: Icon(Icons.favorite),
                      label: Text('First'),
                    ),
                    NavigationRailDestination(
                      icon: Icon(Icons.bookmark_border),
                      selectedIcon: Icon(Icons.book),
                      label: Text('Second'),
                    ),
                    NavigationRailDestination(
                      icon: Icon(Icons.star_border),
                      selectedIcon: Icon(Icons.star),
                      label: Text('Third'),
                    ),
                  ],
                ),
                VerticalDivider(thickness: 1, width: 1),
                // This is the main content.
                Expanded(
                  child: Center(
                    child: Text('selectedIndex: $_selectedIndex'),
                  ),
                )
              ],
            ),
          );
        }
      }
      

      查找现场演示here

      Here是官方文档。

      【讨论】:

        【解决方案3】:

        它于 2020 年 5 月 7 日随 Flutter 1.17 release 一起发布。一个快速的search“导航轨道颤动”会成功的。

        The documentation包括一个现场演示和示例代码。

        int _selectedIndex = 0;
        
         @override
         Widget build(BuildContext context) {
           return Scaffold(
             body: Row(
               children: <Widget>[
                 NavigationRail(
                   selectedIndex: _selectedIndex,
                   onDestinationSelected: (int index) {
                     setState(() {
                       _selectedIndex = index;
                     });
                   },
                   labelType: NavigationRailLabelType.selected,
                   destinations: [
                     NavigationRailDestination(
                       icon: Icon(Icons.favorite_border),
                       selectedIcon: Icon(Icons.favorite),
                       label: Text('First'),
                     ),
                     NavigationRailDestination(
                       icon: Icon(Icons.bookmark_border),
                       selectedIcon: Icon(Icons.book),
                       label: Text('Second'),
                     ),
                     NavigationRailDestination(
                       icon: Icon(Icons.star_border),
                       selectedIcon: Icon(Icons.star),
                       label: Text('Third'),
                     ),
                   ],
                 ),
                 VerticalDivider(thickness: 1, width: 1),
                 // This is the main content.
                 Expanded(
                   child: Center(
                     child: Text('selectedIndex: $_selectedIndex'),
                   ),
                 )
               ],
             ),
           );
         }

        要升级,请运行flutter upgrade,它将从 github 下载最新版本。

        【讨论】:

          【解决方案4】:

          注意:导航栏适用于具有宽视口的布局,例如桌面网络或平板电脑横向布局。对于较小的布局,例如移动肖像,应使用BottomNavigationBar

          int _index = 0;
          
          @override
          Widget build(BuildContext context) {
            return Scaffold(
              body: Row(
                children: <Widget>[
                  NavigationRail(
                    selectedIndex: _index,
                    onDestinationSelected: (index) => setState(() => _index = index),
                    extended: true,
                    destinations: [
                      NavigationRailDestination(
                        icon: Icon(Icons.favorite_border),
                        label: Text('First'),
                      ),
                      NavigationRailDestination(
                        icon: Icon(Icons.bookmark_border),
                        label: Text('Second'),
                      ),
                      NavigationRailDestination(
                        icon: Icon(Icons.star_border),
                        label: Text('Third'),
                      ),
                    ],
                  ),
                  // This is the main content.
                  Expanded(child: Center(child: Text('Index: $_index')))
                ],
              ),
            );
          }
          

          【讨论】:

          • 稍微正确。在桌面上它打开的抽屉,而在平板电脑上它的导航栏。
          【解决方案5】:

          NavigationRail 看起来很整洁。但我注意到没有办法保存小部件状态,所以它总是被重新创建。甚至 AutomaticKeepAliveClientMixin 都不起作用。

          【讨论】:

            猜你喜欢
            • 2020-07-14
            • 2019-11-03
            • 2021-11-24
            • 2019-06-04
            • 2020-10-10
            • 2019-07-01
            • 1970-01-01
            • 2019-12-16
            • 1970-01-01
            相关资源
            最近更新 更多