Flutter自适应导航插件adaptive_navigation_widget的使用

发布于 1周前 作者 htzhanglong 来自 Flutter

Flutter 自适应导航插件 adaptive_navigation_widget 的使用

该插件提供了一个可以根据屏幕大小显示不同类型的导航的组件。本文档将详细介绍如何使用 adaptive_navigation_widget 插件。

功能

  • 可定制的断点
  • 可定制的导航组件
  • 易于与 GoRouter 等包集成

Gif of the widget in action.

支持的导航类型

  • 底部导航栏
  • 抽屉
  • 铁轨 / 扩展铁轨
  • 永久抽屉

如果底部和铁轨导航的目标数量超过允许的数量,则会添加一个包含剩余目标的抽屉。

底部导航栏 抽屉 铁轨 扩展铁轨 永久抽屉

使用

使用示例在 /example/lib/main.dart 中展示。

示例代码

import 'package:adaptive_navigation_widget/adaptive_navigation_widget.dart';
import 'package:flutter/material.dart';

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

/// 一个非常基础的例子来展示 [AdaptiveNavigation] 的使用。
///
/// 它使用了 [IndexedStack] 来显示不同的屏幕。
class Example extends StatefulWidget {
  const Example({Key? key}) : super(key: key);

  [@override](/user/override)
  State<Example> createState() => _ExampleState();
}

class _ExampleState extends State<Example> {
  int _index = 0;

  final List<AdaptiveDestination> destinations = [
    const AdaptiveDestination(
      initialPath: "/home",
      icon: Icon(Icons.home_outlined),
      selectedIcon: Icon(Icons.home),
      label: "Home",
    ),
    const AdaptiveDestination(
      initialPath: "/feed",
      icon: Icon(Icons.feed_outlined),
      selectedIcon: Icon(Icons.feed),
      label: "Feed",
    ),
    const AdaptiveDestination(
      initialPath: "/profile",
      icon: Icon(Icons.person_outlined),
      selectedIcon: Icon(Icons.person),
      label: "Profile",
    ),
  ];

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData.from(
        useMaterial3: true,
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.blueAccent,
          surfaceTint: Colors.transparent,
        ),
      ),
      home: Builder(builder: (context) {
        return AdaptiveNavigation(
          destinations: destinations,

          /// 设置较小的值以显示自动添加的抽屉。
          navigationBarOverflow: 2,
          railNavigationOverflow: 2,

          /// 使此小部件使用的支架成为主要支架。
          /// 如果没有 appBar,则应设置为 'false'。
          // primary: true, // 默认值。
          appBar: AppBar(
            title: Text(destinations[_index].label),

            /// 匹配铁轨的宽度。
            /// 这样按钮打开抽屉时可以与铁轨项对齐。
            leadingWidth: 80,
          ),
          navigationTypeResolver: (context) {
            final screenWidth = MediaQuery.of(context).size.width;
            if (screenWidth > 1280) {
              return NavigationType.permanentDrawer;
            } else if (screenWidth > 800) {
              return NavigationType.extendedRail;
            } else if (screenWidth > 600) {
              return NavigationType.rail;
            } else {
              return NavigationType.bottom;
            }
          },

          /// 更新索引以切换 [IndexedStack] 显示的内容。
          onDestinationChanged: (context, location, index) {
            setState(() {
              _index = index;
            });
          },
          child: IndexedStack(
            index: _index,
            children: const [
              Tab(
                title: "Home",
                content: "I am the home tab!",
              ),
              Tab(
                title: "Feed",
                content: "Here could be some feed!",
              ),
              Tab(
                title: "Profile",
                content: "This is me!",
              ),
            ],
          ),
        );
      }),
    );
  }
}

/// 简单的占位屏幕。
class Tab extends StatelessWidget {
  const Tab({
    required this.title,
    required this.content,
    Key? key,
  }) : super(key: key);

  final String title;
  final String content;

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      /// 'false' 因为主框架使用了显示主要 appBar 的外层 Scaffold。
      primary: false,
      backgroundColor: Colors.blueAccent.withOpacity(0.3),
      body: Center(
        child: Text(content),
      ),
    );
  }
}

/// 展示如何访问 [AdaptiveNavigation] 使用的小部件的键以控制抽屉。
class OpenDrawerButton extends StatelessWidget {
  const OpenDrawerButton({Key? key}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    final navigationScaffoldKeyProvider = NavigationScaffoldKeyProvider.maybeOf(context);

    if (navigationScaffoldKeyProvider?.scaffoldKey.currentState?.hasDrawer ?? false) {
      return IconButton(
        padding: EdgeInsets.zero,
        onPressed: () => navigationScaffoldKeyProvider?.scaffoldKey.currentState?.openDrawer(),
        icon: const Icon(Icons.menu),
      );
    } else {
      return const SizedBox(
        width: 0,
        height: 0,
      );
    }
  }
}

更多关于Flutter自适应导航插件adaptive_navigation_widget的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter自适应导航插件adaptive_navigation_widget的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何使用 adaptive_navigation_widget 插件的示例代码。这个插件可以帮助你在Flutter应用中实现自适应导航栏。

首先,你需要在你的 pubspec.yaml 文件中添加依赖:

dependencies:
  flutter:
    sdk: flutter
  adaptive_navigation_widget: ^最新版本号 # 请替换为实际的最新版本号

然后运行 flutter pub get 来获取依赖。

接下来,我们来看一个完整的示例,展示如何使用 adaptive_navigation_widget

import 'package:flutter/material.dart';
import 'package:adaptive_navigation_widget/adaptive_navigation_widget.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Adaptive Navigation Widget Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: AdaptiveNavigationScaffold(
        drawer: Drawer(
          child: ListView(
            padding: EdgeInsets.zero,
            children: <Widget>[
              DrawerHeader(
                child: Text('Drawer Header'),
                decoration: BoxDecoration(
                  color: Colors.blue,
                ),
              ),
              ListTile(
                title: Text('Item 1'),
                onTap: () {
                  Navigator.pop(context); // 关闭抽屉菜单
                  // 处理点击事件
                },
              ),
              ListTile(
                title: Text('Item 2'),
                onTap: () {
                  Navigator.pop(context); // 关闭抽屉菜单
                  // 处理点击事件
                },
              ),
            ],
          ),
        ),
        appBar: AppBar(
          title: Text('Home'),
        ),
        body: Center(
          child: Text('Body Content'),
        ),
        bottomNavigationBar: AdaptiveBottomNavigationBar(
          settings: AdaptiveThemeSettings(
            darkTheme: ThemeData(
              brightness: Brightness.dark,
            ),
            lightTheme: ThemeData(
              brightness: Brightness.light,
            ),
          ),
          items: [
            AdaptiveBottomNavigationBarItem(
              icon: Icon(Icons.home),
              title: Text('Home'),
            ),
            AdaptiveBottomNavigationBarItem(
              icon: Icon(Icons.search),
              title: Text('Search'),
            ),
            AdaptiveBottomNavigationBarItem(
              icon: Icon(Icons.add),
              title: Text('Add'),
            ),
            AdaptiveBottomNavigationBarItem(
              icon: Icon(Icons.profile),
              title: Text('Profile'),
            ),
          ],
          currentIndex: 0,
          onTap: (index) {
            // 处理底部导航点击事件
            print('Navigated to index: $index');
          },
        ),
      ),
    );
  }
}

在这个示例中,我们做了以下几件事:

  1. 创建了一个基本的Flutter应用:通过 MaterialAppMyApp 类。
  2. 使用了 AdaptiveNavigationScaffold:这个组件结合了抽屉导航栏(Drawer)和自适应底部导航栏(AdaptiveBottomNavigationBar)。
  3. 配置了抽屉导航栏(Drawer):包括一个头部和两个列表项。
  4. 设置了自适应底部导航栏(AdaptiveBottomNavigationBar):包括四个导航项,每个导航项有一个图标和标题。
  5. 处理了底部导航栏的点击事件:通过 onTap 回调,你可以在这里添加页面导航逻辑。

你可以根据需求进一步定制和扩展这个示例。希望这个示例对你有帮助!

回到顶部