Flutter 中的路由使用

484 阅读4分钟

Navigator 1.0

1.跨屏动画组件

当用户从一个屏幕导航到另一个屏幕时,引导他们浏览应用程序通常很有帮助。引导用户浏览应用程序的常用技术是将小部件从一个屏幕动画到下一个屏幕。这创建了连接两个屏幕的视觉锚点。

简单来说就是同样一个图片。在两个页面切换时由第一个页面动画过度到第二个页面.

使用Hero小部件将小部件从一个屏幕动画到下一个屏幕。此配方使用以下步骤:

  1. 创建两个显示相同图像的屏幕。
Hero(
  tag: 'imageHero',
  child: Image.network(
    'https://picsum.photos/250?image=9',
  ),
)
  1. Hero小部件添加到第一个屏幕。
  2. Hero小部件添加到第二个屏幕。
  3. 他们的tag相同的话系统会自动执行相应的动画
import 'package:flutter/material.dart';

void main() => runApp(const HeroApp());

class HeroApp extends StatelessWidget {
  const HeroApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Transition Demo',
      home: MainScreen(),
    );
  }
}

class MainScreen extends StatelessWidget {
  const MainScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Main Screen'),
      ),
      body: GestureDetector(
        onTap: () {
          Navigator.push(context, MaterialPageRoute(builder: (context) {
            return const DetailScreen();
          }));
        },
        child: Hero(
          tag: 'imageHero',
          child: Image.network(
            'https://picsum.photos/250?image=9',
          ),
        ),
      ),
    );
  }
}

class DetailScreen extends StatelessWidget {
  const DetailScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: GestureDetector(
        onTap: () {
          Navigator.pop(context);
        },
        child: Center(
          child: Hero(
            tag: 'imageHero',
            child: Image.network(
              'https://picsum.photos/250?image=9',
            ),
          ),
        ),
      ),
    );
  }
}

把此类拷贝到flutter中运行即可看到相应的动画切换

跳转到新界面后返回

1. 跳转到新页面

第一个界面点击时执行

onTap: () {
          Navigator.push(context, MaterialPageRoute(builder: (context) {
            return const DetailScreen();
          }));
        }

2. 返回原页面

在第二个界面点击按钮时执行

onPressed: () {
  Navigator.pop(context);
}

利用命名路由跳转

1.创建两个 FirstScreenSecondScreen

2.在MaterialApp中定义路由

MaterialApp(
  title: 'Named Routes Demo',
  // Start the app with the "/" named route. In this case, the app starts
  // on the FirstScreen widget.
  initialRoute: '/',
  routes: {
    // When navigating to the "/" route, build the FirstScreen widget.
    '/': (context) => const FirstScreen(),
    // When navigating to the "/second" route, build the SecondScreen widget.
    '/second': (context) => const SecondScreen(),
  },
)

3.利用命名路由的方式导航到指定界面

// Within the `FirstScreen` widget
onPressed: () {
  // Navigate to the second screen using a named route.
  Navigator.pushNamed(context, '/second');
}

4.返回上一个界面

// Within the SecondScreen widget
onPressed: () {
  // Navigate back to the first screen by popping the current route
  // off the stack.
  Navigator.pop(context);
}

命名路由中使用参数传值

当我们在跳转页面时有的时候需要携带上一个页面的参数,此时就需要在命名路由中传参。

1.定义要传参的argument

// You can pass any object to the arguments parameter.
// In this example, create a class that contains both
// a customizable title and message.
class ScreenArguments {
  final String title;
  final String message;
  ScreenArguments(this.title, this.message);
}

2.创建接收参数的页面

// A Widget that extracts the necessary arguments from
// the ModalRoute.
class ExtractArgumentsScreen extends StatelessWidget {
  const ExtractArgumentsScreen({Key? key}) : super(key: key);

  static const routeName = '/extractArguments';

  @override
  Widget build(BuildContext context) {
    // Extract the arguments from the current ModalRoute
    // settings and cast them as ScreenArguments.
    final args = ModalRoute.of(context)!.settings.arguments as ScreenArguments;

    return Scaffold(
      appBar: AppBar(
        title: Text(args.title),
      ),
      body: Center(
        child: Text(args.message),
      ),
    );
  }
}

3.跳转页面并传参

// A button that navigates to a named route.
// The named route extracts the arguments
// by itself.
ElevatedButton(
  onPressed: () {
    // When the user taps the button,
    // navigate to a named route and
    // provide the arguments as an optional
    // parameter.
    Navigator.pushNamed(
      context,
      ExtractArgumentsScreen.routeName,
      arguments: ScreenArguments(
        'Extract Arguments Screen',
        'This message is extracted in the build method.',
      ),
    );
  },
  child: const Text('Navigate to screen that extracts arguments'),
),

4.利用 onGenerateRoute 方式进行参数提取并把参数放进Widget组件中

这种方式需要额外配置MaterialApp中的onGenerateRoute方法

MaterialApp(
  // Provide a function to handle named routes.
  // Use this function to identify the named
  // route being pushed, and create the correct
  // Screen.
  onGenerateRoute: (settings) {
    // If you push the PassArguments route
    if (settings.name == PassArgumentsScreen.routeName) {
      // Cast the arguments to the correct
      // type: ScreenArguments.
      final args = settings.arguments as ScreenArguments;

      // Then, extract the required data from
      // the arguments and pass the data to the
      // correct screen.
      return MaterialPageRoute(
        builder: (context) {
          return PassArgumentsScreen(
            title: args.title,
            message: args.message,
          );
        },
      );
    }
    // The code only supports
    // PassArgumentsScreen.routeName right now.
    // Other values need to be implemented if we
    // add them. The assertion here will help remind
    // us of that higher up in the call stack, since
    // this assertion would otherwise fire somewhere
    // in the framework.
    assert(false, 'Need to implement ${settings.name}');
    return null;
  },
)

从新开页面返回数据到上一个页面

1. 页面跳转并接收返回值

final result = await Navigator.push(
      context,
      // Create the SelectionScreen in the next step.
      MaterialPageRoute(builder: (context) => const SelectionScreen()),
    );

2. 返回界面时返给上一个页面值

// Close the screen and return "Yep!" as the result.
Navigator.pop(context, 'Yep!');

发送数据到新界面(总是感觉跟上面的重复)

1. 构造方法传参携带数据跳转

onTap: () {
        Navigator.push(
          context,
          MaterialPageRoute(
            builder: (context) => DetailScreen(todo: todos[index]),
          ),
        );
      },

2. RouteSettings传参携带数据跳转

onTap: () {
        Navigator.push(
          context,
          MaterialPageRoute(
            builder: (context) => const DetailScreen(),
            // Pass the arguments as part of the RouteSettings. The
            // DetailScreen reads the arguments from these settings.
            settings: RouteSettings(
              arguments: todos[index],
            ),
          ),
        );
      },

Navigator 2.0

针对于flutter 的Navigator 2.0 官网并没有给出好的文档和说明,包括视频也是感觉没有看明白,面见到两篇文章感觉还可以,推荐给大家。全靠自悟!^^!地址如下: Flutter navigator 2.0原理详解 / Flutter navigator 2.0全面解析望诸君不走弯路。