Flutter导航管理插件nav的使用

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

Flutter导航管理插件nav的使用

Welcome to Nav 👋

Version License: Apache 2.0

提供了一种简单的方式来实现页面导航,包含许多路由功能。支持Android和iOS平台。

Nav Tag Sample

Install

pubspec.yaml文件中添加nav依赖:

dependencies:
  nav: ^{latest version}

Usage

  1. 在您的App State中添加Nav mixin:

    import 'package:nav/nav.dart';
    
    class _MyAppState extends State<MyApp> with Nav 
    
  2. 覆盖get navigatorKey方法,并提供您在MaterialApp.navigatorKey中使用的key:

    class MyApp extends StatefulWidget {
      static GlobalKey<NavigatorState> navigatorKey = GlobalKey();
      // This widget is the root of your application.
    
      @override
      _MyAppState createState() => _MyAppState();
    }
    
    class _MyAppState extends State<MyApp> with Nav {
      @override
      GlobalKey<NavigatorState> get navigatorKey => MyApp.navigatorKey;
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          navigatorKey: navigatorKey,
          ...
    
  3. 使用push方法进行页面跳转:

    //dynamic
    Nav.push(Widget, navAni: NavAni.Blink);
    
    //or
    Nav.pushFromRight(Widget);
    Nav.pushFromLeft(Widget);
    Nav.pushFromTop(Widget);
    Nav.pushFromBottom(Widget);
    Nav.pushReplacement(Widget);
    Nav.pushWithRippleEffect(Widget, centerAlignment : Alignment.bottomRight, centerOffset : Offset(10, 10));
    Nav.clearAllAndPush(Widget);
    
    enum NavAni { Left, Right, Top, Bottom, Fade, Ripple, Blink }
    
  4. 所有方法都可以返回值:

    //from bottom screen
    final result = await Nav.pushFromRight(TopScreen) //you can get result from TopWidget
    
    //from top screen
    Nav.pop(context, result: {"key": "value", "key2": 2})
    
  5. 可以定义类型与NavScreenpushResult方法配合使用:

    TopScreen extends StatelessWidget with NavScreen<String> 
    
    or
    
    TopScreen extends StatefulWidget with NavScreen<String>
    
    
    ///from bottom screen
    final result = await Nav.pushResult(TopScreen()); ///result type will be String? 
    
    ///from top screen
    ///return Type will be fixed by Generic NavScreen<Result>
    popResult(context, result: 'Data to return'); ///from Widget
    
    widget.popResult(context, result: 'Data to return'); ///from State
    

示例代码

下面是一个完整的示例demo,展示了如何使用nav插件进行页面导航:

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:nav/nav.dart';
import 'package:nav/screen/nav_screen.dart';

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

class MyApp extends StatefulWidget {
  static GlobalKey<NavigatorState> navigatorKey = GlobalKey();

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

class _MyAppState extends State<MyApp> with Nav {
  @override
  GlobalKey<NavigatorState> get navigatorKey => MyApp.navigatorKey;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorKey: navigatorKey,
      title: 'Nav Demo',
      theme: ThemeData(
        scaffoldBackgroundColor: Colors.white,
        iconTheme: const IconThemeData(color: Colors.blue),
        textTheme: const TextTheme(),
        bottomSheetTheme: const BottomSheetThemeData(backgroundColor: Colors.transparent),
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget with NavScreen<SimpleResult> {
  MyHomePage({Key? key, this.navType}) : super(key: key);

  final NavType? navType;

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

class _MyHomePageState extends State<MyHomePage> {
  bool showBackButton = false;
  Color? bgColor;

  bool get isHome => !showBackButton;

  @override
  void initState() {
    bgColor = getRandomColor();
    super.initState();
  }

  void checkCanPop() async {
    if (await Nav.canPop()) {
      setState(() {
        this.showBackButton = true;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: bgColor,
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          final result = await MessageDialog('Test String').show();
          print(result);
        },
        tooltip: 'Ripple',
        child: Icon(Icons.open_in_new),
      ),
      body: SafeArea(
        child: Stack(
          children: [
            Column(
              children: [
                Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    IconButton(
                      onPressed: () async => onResult(
                          context,
                          await Nav.pushFromTop(
                              MyHomePage(navType: NavType.Top))),
                      icon: icon(Icons.vertical_align_bottom),
                    )
                  ],
                ),
                Expanded(
                  child: Container(
                    child: Center(
                      child: Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        children: [
                          IconButton(
                            onPressed: () async {
                              onResult(
                                  context,
                                  await Nav.pushFromLeft(MyHomePage(
                                      navType: NavType.Left)));
                            },
                            icon: icon(Icons.keyboard_arrow_right),
                          ),
                          Column(
                            mainAxisAlignment: MainAxisAlignment.center,
                            children: [
                              InkWell(
                                child: icon(iconData),
                                onTap: () {
                                  if (isHome) {
                                    Nav.clearAllAndPush(MyHomePage(
                                      navType: NavType.ClearAll,
                                    ));
                                  } else {
                                    widget.popResult(context, SimpleResult.failure());
                                  }
                                },
                              ),
                              isHome
                                  ? Text("Click an Arrow",
                                      style: TextStyle(
                                          color: Colors.white,
                                          fontSize: 20,
                                          fontWeight: FontWeight.w700))
                                  : Container(),
                            ],
                          ),
                          IconButton(
                            onPressed: () async => onResult(
                                context,
                                await Nav.pushFromRight(MyHomePage(
                                    navType: NavType.Right))),
                            icon: icon(Icons.keyboard_arrow_left),
                          ),
                        ],
                      ),
                    ),
                  ),
                ),
                Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    IconButton(
                      onPressed: () async => onResult(
                          context,
                          await Nav.pushFromBottom(
                              MyHomePage(navType: NavType.Bottom))),
                      icon: icon(Icons.vertical_align_top),
                    )
                  ],
                ),
              ],
            ),
            !showBackButton
                ? Container()
                : IconButton(
                    onPressed: () => Nav.pop(context),
                    icon: icon(Platform.isIOS
                        ? Icons.arrow_back_ios
                        : Icons.arrow_back),
                  )
          ],
        ),
      ),
    );
  }

  Icon icon(IconData data) {
    return Icon(
      data,
      size: 30,
      color: Colors.white,
    );
  }

  IconData get iconData {
    switch (widget.navType) {
      case NavType.Top:
        return Icons.vertical_align_top;
      case NavType.Bottom:
        return Icons.vertical_align_bottom;
      case NavType.Left:
        return Icons.keyboard_arrow_left;
      case NavType.Right:
        return Icons.keyboard_arrow_right;
      case NavType.Ripple:
        return Icons.archive;
      case NavType.ClearAll:
        return Icons.border_clear;
      default:
        return Icons.home;
    }
  }

  SnackBar createSnackBar(BuildContext context, String message) {
    return SnackBar(
        elevation: 0,
        behavior: SnackBarBehavior.fixed,
        backgroundColor: Colors.transparent,
        content: GestureDetector(
          onTap: () {},
          child: Container(
            color: Colors.transparent,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.end,
              children: <Widget>[
                Center(
                  child: Container(
                      padding: EdgeInsets.symmetric(horizontal: 20, vertical: 11),
                      child: Center(
                        child: Text(message,
                            style: TextStyle(
                              color: Colors.white,
                              fontSize: 14,
                              fontStyle: FontStyle.normal,
                            )),
                      ),
                      decoration: BoxDecoration(
                          color: Color(0xff5a8fee),
                          borderRadius: BorderRadius.circular(5))),
                ),
              ],
            ),
          ),
        ));
  }

  void onResult(BuildContext context, SimpleResult result) {
    if (result.isSuccess) {
      final snackbar =
          createSnackBar(context, "Result is Success: ${result.toString()}");
      ScaffoldMessenger.of(context).showSnackBar(snackbar);
    }
  }
}

这个示例展示了如何使用nav插件进行页面导航、传递参数以及处理返回结果。希望这对您有所帮助!


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

1 回复

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


在Flutter中,flutter_navigator 或者更常见的 flutter/material 提供的导航功能是实现页面跳转和管理的核心。虽然没有一个特定的名为 nav 的官方插件,但通常我们指的是 Flutter 自带的导航功能。以下是如何使用 Flutter 的导航管理功能的代码示例。

1. 设置基本导航

首先,确保你的 Flutter 项目已经设置好,并包含必要的依赖(主要是 flutter/material)。

dependencies:
  flutter:
    sdk: flutter

2. 创建主页面和次级页面

主页面 (main.dart)

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('First Screen'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(builder: (context) => SecondScreen()),
            );
          },
          child: Text('Go to Second Screen'),
        ),
      ),
    );
  }
}

次级页面 (second_screen.dart)

import 'package:flutter/material.dart';

class SecondScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Second Screen'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.pop(context);
          },
          child: Text('Go Back'),
        ),
      ),
    );
  }
}

3. 使用命名路由(可选)

如果你的应用有多个页面,使用命名路由可以使导航管理更加清晰。

修改主页面以使用命名路由

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      initialRoute: '/',
      routes: {
        '/': (context) => MyHomePage(),
        '/second': (context) => SecondScreen(),
      },
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('First Screen'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.pushNamed(context, '/second');
          },
          child: Text('Go to Second Screen'),
        ),
      ),
    );
  }
}

4. 传递参数

有时候,你可能需要在页面之间传递数据。这可以通过构造函数参数或 Navigator 的参数功能实现。

修改次级页面以接收参数

import 'package:flutter/material.dart';

class SecondScreen extends StatelessWidget {
  final String message;

  SecondScreen({required this.message});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Second Screen'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(message),
            ElevatedButton(
              onPressed: () {
                Navigator.pop(context);
              },
              child: Text('Go Back'),
            ),
          ],
        ),
      ),
    );
  }
}

修改主页面以传递参数

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      initialRoute: '/',
      routes: {
        '/': (context) => MyHomePage(),
        '/second': (context) => SecondScreen(), // Note: We will instantiate with arguments later
      },
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('First Screen'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.pushNamed(
              context,
              '/second',
              arguments: {'message': 'Hello from First Screen!'},
            ).then((result) {
              // Handle result if needed
            });
          },
          child: Text('Go to Second Screen with Message'),
        ),
      ),
    );
  }
}

SecondScreen 中接收参数:

import 'package:flutter/material.dart';

class SecondScreen extends StatelessWidget {
  SecondScreen({Key? key, required this.message}) : super(key: key);

  final String message;

  @override
  Widget build(BuildContext context) {
    final routeArgs = ModalRoute.of(context)?.settings.arguments as Map<String, dynamic>;
    String msg = routeArgs['message'] ?? 'No message received';

    return Scaffold(
      appBar: AppBar(
        title: Text('Second Screen'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(msg),
            ElevatedButton(
              onPressed: () {
                Navigator.pop(context);
              },
              child: Text('Go Back'),
            ),
          ],
        ),
      ),
    );
  }
}

这段代码展示了如何在 Flutter 中使用导航管理功能,包括基本的页面跳转、使用命名路由以及页面间传递参数。希望这些示例对你有帮助!

回到顶部