24、Flutter之Navigator进行局部跳转页面

1,402 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第24天,点击查看活动详情

Navigator

Navigator 是管理路由的控件,通常情况下直接使用Navigator.of(context)的方法来跳转页面,之所以可以直接使用Navigator.of(context)是因为在WidgetsApp中使用了此控件,应用程序的根控件通常是MaterialApp,MaterialApp包含WidgetsApp,所以可以直接使用Navigator的相关属性。 需要关注: 1.MaterialApp内置了一个Navigator对象。 2.一个App中多个Navigator对象在调用Navigator.of(context)要注意的事项。 基本用法:

class MyNavigator extends StatefulWidget {
  const MyNavigator({Key? key}) : super(key: key);
 
  @override
  _MyNavigatorState createState() => _MyNavigatorState();
}
 
class _MyNavigatorState extends State<MyNavigator> {
  @override
  Widget build(BuildContext context) {
    return  Scaffold(
      appBar: getAppBar('Navigator跳转'),
      body: buildNavigator,
    );
  }
  Navigator get buildNavigator{
    return Navigator(
      initialRoute: '/',
      onGenerateRoute: (RouteSettings settings) {
        WidgetBuilder builder;
        switch(settings.name){
          case'home':
            builder=(context)=>OnePage();
            break;
          case 'user':
            builder=(context)=>TwoPage();
            break;
          default:
            builder=(context)=>OnePage();
            break;
        }
        return MaterialPageRoute(builder: builder, settings: settings);
      },
    );
  }
}

initialRoute表示初始化路由,onGenerateRoute表示根据RouteSettings生成路由。

头条客户端举报场景

点击弹出相关信息,点击其中的局部,会在当前小窗户内跳转到举报页面,效果如下 111.gif

此场景就是使用Navigator的典型场景,点击举报,并不是全屏切换页面,而是仅仅在当前弹出的页面进行切换。 首页:

class PageA extends StatelessWidget {
  const PageA({Key? key}) : super(key: key);
 
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        height: 350,
        width: 300,
        child: Navigator(
          initialRoute: '/',
          onGenerateRoute: (RouteSettings settins) {
            WidgetBuilder builder;
            switch (settins.name) {
              case '/':
                builder = (context) => PageC();
                break;
              default:
                builder = (context) => PageD();
                break;
 
            }
            return MaterialPageRoute(builder: builder);
          },
        ),
      ),
    );
  }
}

Navigator的初始化路由为PageC页面,PageC页面代码如下:

import 'package:demo202112/MyNavigator/wy_paged.dart';
import 'package:flutter/material.dart';

/**
 * @Author wywinstonwy
 * @Date 2022/10/10 9:48 下午
 * @Description:
 */

class PageC extends StatelessWidget {
  @override
  Widget build(BuildContext context) {

    return Center(
      child: Card(
        child: Column(
          children: <Widget>[
            _buildItem(Icons.clear, '不感兴趣', '减少这类内容',),
            Divider(),
            _buildItem(Icons.access_alarm, '举报', '标题夸张,内容质量差 等',
                showArrow: true, onPress: () {
                  Navigator.of(context).push(MaterialPageRoute(builder: (context) {
                    return PageD();
                  }
                  )
                  );
                }),
            Divider(),
            _buildItem(Icons.perm_identity, '拉黑作者:汽车执行', '', ),
            Divider(),
            _buildItem(Icons.account_circle, '屏蔽', 'seqing视频、驾驶员等',),
          ],
        ),
      ),
    );
  }



  _buildItem(IconData iconData, String title, String content,
      {bool showArrow = false,  Function() ? onPress}) {
    return Row(
      children: <Widget>[
        Icon(iconData),
        SizedBox(
          width: 20,
        ),
        Expanded(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              Text(
                title,
                style: TextStyle(fontSize: 18),
              ),
              Text(
                content,
                style: TextStyle(
                    color: Colors.black.withOpacity(.5), fontSize: 14),
              )
            ],
          ),
        ),
        !showArrow
            ? Container()
            : IconButton(
          icon: Icon(Icons.arrow_forward_ios),
          iconSize: 16,
          onPressed:  onPress,
        ),
      ],
    );
  }
}

PageC页面跳转到PageD页面,PageD页面代码如下:

class PageD extends StatefulWidget {
  const PageD({Key? key}) : super(key: key);
 
  @override
  _PageDState createState() => _PageDState();
}
 
class _PageDState extends State<PageD> {
  @override
  Widget build(BuildContext context) {
     return Column(
       children: [ElevatedButton(onPressed:(){
         Navigator.pop(context);
       }, child: Text('返回')),
       Divider(),
       Text('虚假信息举报')  
       
       ],
     );
  }
}

Navigator Widget Tree

通过 DevTools 查看一个普通 Flutter App 的 Widget 树结构,与 Navigator 相关的 Widget 如下图:

图片.png

路由传参和返回携带回调参数

如构建登录页面时候push携带一些参数,登录后返回或者状态改变时候携带回去必要参数,代码如下:

// 定义HomePage
class HomePage extends StatelessWidget {
  const HomePage({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("登录"),
      ),
      body: ElevatedButton(
        onPressed: () async {
          // 实现路由跳转
          var result = await Navigator.pushNamed(context, 'menu',
              arguments: {'name': 'title'});
          print(result);
        },
        child: const Text('登录'),
      ),
    );
  }
}
// 定义MenuPage
class MenuPage extends StatelessWidget {
  const MenuPage({Key? key}) : super(key: key);
  @override
  // 接收传参
  Widget build(BuildContext context) {
    dynamic argumentsData = ModalRoute.of(context)?.settings.arguments;
    return Scaffold(
      appBar: AppBar(
        title: Text('菜单' + argumentsData.toString()),
      ),
      body: ElevatedButton(
        onPressed: () {
          Navigator.pop(context, {'name': "Navigator.pop传参"});
        },
        child: const Text("返回"),
      ),
    );
  }
}

总结

在实际项目中,对于不需要携带参数的Page可以直接定义全局的Navigator配置routers进行统一管理,对于需要携带参数的可以单独定义工具类进行处理,留出参数和返回参数的情况。