Flutter 学习笔记(八)基础路由 / 命名路由

135 阅读3分钟

基本路由

实现点击按钮跳转到search页面并且传递参数以及在搜索页面添加返回按钮

image.png

image.png

//- home 界面

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

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Row(
        crossAxisAlignment: CrossAxisAlignment.center,
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          ElevatedButton(
            onPressed: () {
              Navigator.of(context)
               .push(MaterialPageRoute(builder: (BuildContext content) {
                return SearchPage("我是跳转传递的参数123123");
              }));
            },
            child: Text("跳转搜索页面"),
            style: TextButton.styleFrom(
                textStyle: TextStyle(fontSize: 20),
                backgroundColor: Colors.amber),
          )
        ]);
  }
}
//- search 界面

import 'package:flutter/material.dart';

class SearchPage extends StatelessWidget {
  String text;
  SearchPage(this.text);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        floatingActionButton: FloatingActionButton(
            child: Text("返回"),
            onPressed: () {
              Navigator.of(context).pop();
            },
        ),
        appBar: AppBar(title: Text("搜索页面")),
        body: Text(this.text));
  }
}

命名路由

注意事项:

image.png

如果发现以上错误,是因为子页面使用了MaterialApp进行包裹,在根页面进行跳转到其他页面时候也使用了命名路由,在使用Navigator命名路由时候,子页面不能用MaterialApp进行包裹;

命名路由跳转案例代码:

image.png

image.png

main.dart

import 'package:flutter/material.dart';
import 'pages/tabs.dart';
import 'pages/classfiy.dart';
import 'pages/Search.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: Tabs(), routes: {
      '/classfiy': (context) => Classify(),
      '/search': (context) => SearchPage(),
    });
  }
}

search页面

import 'package:flutter/material.dart';

class SearchPage extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        child: Text("返回"),
        onPressed: () {
          Navigator.of(context).pop();
        },
      ),
      appBar: AppBar(title: Text("搜索页面")),
      body: Text("搜索页面"),
    );
  }
}

Classify页面

import 'package:flutter/material.dart';

class Classify extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Text("分类页面"),
    );
  }
}

tabs 页面

//- 为了案例完整性,将代码放到这里,这个和路由无关

import 'package:flutter/material.dart';
import 'home.dart';
import 'classfiy.dart';
import 'setting.dart';

class Tabs extends StatefulWidget {
  Tabs({Key? key}) : super(key: key);

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

class _TabsState extends State<Tabs> {
  int _currentIndex = 0;
  List pageList = [
    HomePage(),
    Classify(),
    Setting(),
  ];
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: Text("Hello Demo")),
        body: pageList[_currentIndex],
        bottomNavigationBar: BottomNavigationBar(
          currentIndex: _currentIndex,
          onTap: (int index) {
            setState(() {
              this._currentIndex = index;
            });
          },
          fixedColor: Colors.green,
          // type: BottomNavigationBarType.fixed,
          items: [
            BottomNavigationBarItem(label: "首页", icon: Icon(Icons.home)),
            BottomNavigationBarItem(label: "分类", icon: Icon(Icons.category)),
            BottomNavigationBarItem(label: "设置", icon: Icon(Icons.settings)),
          ],
        ));
  }
}

命名路由跳转传递参数案例代码:

第一种传递方法:

  1. 首先,定义需要传递给新路由的参数
//- 定义了一个utils.js 文件来存放需要传递的路由参数

class nameBean {
  String name;
  int age;
  nameBean(this.name, this.age);
}
  1. search 页面提取参数
import 'package:flutter/material.dart';
import 'utilts.dart';

class SearchPage extends StatelessWidget {
  String title; //- 这个是构造函数传递的参数
  SearchPage(this.title);

  @override
  Widget build(BuildContext context) {
    //- 这个是utils定义好的路由参数进行提取
    final nameObj = ModalRoute.of(context)!.settings.arguments as nameBean;

    return Scaffold(
      floatingActionButton: FloatingActionButton(
        child: Text("返回"),
        onPressed: () {
          Navigator.of(context).pop();
        },
      ),
      appBar: AppBar(title: Text("${this.title}")),
      body: Text("${nameObj.name}---${nameObj.age}"), //- 直接获取需要的参数即可
    );
  }
}

  1. home页面创建按钮进行页面跳转并且传递参数
import 'package:flutter/material.dart';
import 'utilts.dart';

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(children: <Widget>[
      ElevatedButton(
        onPressed: () {
          Navigator.pushNamed(context, '/search',
              arguments: nameBean("李四", 20));
        },
        child: Text("跳转搜索页面"),
      )
    ]);
  }
}
  1. main.dart 文件进行命名路由定义
import 'package:flutter/material.dart';
import 'pages/tabs.dart';
import 'pages/Search.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
       home: Tabs(), 
       routes: {
         '/search': (context, {arguments}) => SearchPage("hello123"),
    });
  }
}

image.png

image.png

第二种传递方法:

使用onGenerateRoute提取参数

  1. 首先,定义需要传递给新路由的参数
//- 定义了一个utils.js 文件来存放需要传递的路由参数

class nameBean {
  String name;
  int age;
  nameBean(this.name, this.age);
}
  1. search 页面提取参数
import 'package:flutter/material.dart';
import 'utilts.dart';


class SearchPage extends StatelessWidget {
  static const routeName = '/search';

  String name;
  int age;
  String title;
   
  SearchPage({
    Key? key,
    required this.name,
    required this.age,
    required this.title,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        child: Text("返回"),
        onPressed: () {
          Navigator.of(context).pop();
        },
      ),
      appBar: AppBar(title: Text("${this.title}")),
      body: Text("${this.name}---${this.age}"),
    );
  }
}

  1. home页面创建按钮进行页面跳转并且传递参数
import 'package:flutter/material.dart';
import 'utilts.dart';
import 'Search.dart';

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(children: <Widget>[
      ElevatedButton(
        onPressed: () {
          Navigator.pushNamed(context, '/search',
              arguments: nameBean('张三', 20));
        },
        child: Text("跳转搜索页面"),
      ),
    ]);
  }
}
  1. 使用 onGenerateRoute 提取参数
import 'package:flutter/material.dart';
import 'pages/tabs.dart';
import 'pages/Search.dart';
import 'pages/utilts.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Tabs(),
        
        onGenerateRoute: (settings) {
          if (settings.name == SearchPage.routeName) {
            final args = settings.arguments as nameBean;

            return MaterialPageRoute(
              builder: (context) {
                return SearchPage(name: args.name, age: args.age,title: "我是123");
              },
            );
          }

          assert(false, 'Need to implement ${settings.name}');
          return null;
        });
  }
}

image.png

image.png

路由返回上一级页面

Navigator.of(context).pop();

Navigator.of(context).pushReplacementNamed('/registerSecond') 与 Navigator.pushNamed(context, '/r2') 的区别

pushReplacementNamed 比如我们从用户中心页面跳转到了 registerFirst 页面,然后从 registerFirst 页面通过 pushReplacementNamed 跳转到了 registerSecond 页面。这个时候当我们点击 registerSecond 的返回按钮 .pop() 的时候它会直接返回到用户中心

pushNamed 则返回 .pop() 是上一级页面 registerFirst 页面;如果想返回根目录使用Navigator.of(context).pushAndRemoveUntil( new MaterialPageRoute(builder: (context) => new Tabs(index:1)), (route) => route == null );