Детали перехода маршрутизации Flutter и передачи значений (использование Navigator)

Flutter

Если вы хотите прыгать и передавать значения между страницами во Flutter, вам не обойтись без двух маршрутов:

  • базовая маршрутизация
  • именованная маршрутизация

Официально это статическая маршрутизация и динамическая маршрутизация, но я привык называть это именно так, так что пока поговорим об этом!

базовая маршрутизация

базовый прыжок

Перейти к основному маршруту
использоватьpushПерейти на указанную страницу, а затем использоватьpopвернуться на исходную страницу

Однако, когда вы переходите в прошлое, по умолчанию будет кнопка возврата со стрелкой, нажмите, чтобы вернуться

начать кодирование

я здесьmain.dartссылка в документеHome.dartдокумент
существуетHome.dartВ файле есть кнопка, которая, когда я нажимаю на нее, переходит на страницу сведений.

Примечание: при использованииstlСгенерированные статические элементы управления не могут использовать кнопки перехода

Home.dartКод файла:

//Home.dart
import 'package:flutter/material.dart';
import './Detail.dart';

class Home extends StatefulWidget {
  @override
  _HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: <Widget>[
          RaisedButton(
            child: Text('跳到详情页面'),
            onPressed: (){
              //跳转页面
              Navigator.of(context).push(
                MaterialPageRoute(
                  //没有传值
                  builder: (context)=>Detail()
                )
              );
            },
          )
        ],
      ),
    );
  }
}

Когда я нажимаю кнопку, я могу перейти на страницу сведений:
Detail.dartКод файла:

import 'package:flutter/material.dart';

class Detail extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      //浮动按钮
      floatingActionButton: FloatingActionButton(
        child: Text('返回'),
        onPressed: (){
          Navigator.of(context).pop();
        },
      ),
      appBar: AppBar(title: Text("详情页面"),),
      body: Text("详情页面"),
    );
  }
}

Как показано на рисунке, после перепрыгивания по умолчанию будет кнопка возврата, после нажатия можно вернуться.
Вы также можете определить кнопку самостоятельно,использоватьpopметодНажмите, чтобы вернуться

прыжок по значению

Иногда нам нужно передать параметры, когда мы прыгаем,
На этот раз мы должны нести параметры для прыжка, конечно это очень просто

Нам нужно определить переменную на странице с помощью параметров,Обратите внимание, что вам нужно установить значение по умолчанию, если вы не передаете значение, используйте значение по умолчанию
потомПередать значения на целевую страницу при переходе

Home.dartКод файла:

//Home.dart
//只贴按钮的代码,其余的和上面一样

RaisedButton(
	child: Text('跳到详情页面'),
	onPressed: (){
	  //跳转页面
	  Navigator.of(context).push(
		MaterialPageRoute(
		  //传值
		  builder: (context)=>Detail(Test:'我是参数')
		  //没传值
		  //builder: (context)=>Detail()
		)
	  );
	},
  )

Затем получите его на целевой странице, если значение не передано, по умолчанию используется значение по умолчанию, определенное выше.

Detail.dartКод файла:

class Detail extends StatelessWidget {
  //需要定义变量和默认值
  String Test;
  Detail({this.Test='没有给我传值'});
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      //浮动按钮
      floatingActionButton: FloatingActionButton(
        child: Text('返回'),
        onPressed: (){
          Navigator.of(context).pop();
        },
      ),
      appBar: AppBar(title: Text("详情页面"),),
      body: Text(this.Test),
    );
  }
}

получить ценность по возвращении

Иногда нам не нужно передавать значения при прыжке, а при возврате нам нужно получить значения от подкомпонентов

Для иллюстрации используйте следующий пример:

Создайте два новых файла дротикаAddressList.dartа такжеGetAddress.dartфайл, вmian.dartиспользуется вGetAddress.dartдокумент

мы хотим нажатьGetAddress.dartв файлеВыберите адрес для сбора урожаякнопку , перейдите на страницу добавления адреса и после выбора адреса сразу вернитесь на первую страницу с данными и отобразите ее.

Пример кода:

main.dartФайл изменяет только элементы управления, которые необходимо отобразить.

import 'package:flutter/material.dart';
import './address/GetAddress.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("Route"),
        ),
        body: GetAddress()
      ),
    );
  }
}

Обратите внимание, что сбор данных асинхронный, вам нужно добавитьasync、await
Единственный способ изменить данные — использоватьsetStateметод

GetAddress.dartКод файла:

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

class GetAddress extends StatefulWidget {
  @override
  _GetAddressState createState() => _GetAddressState();
}

class _GetAddressState extends State<GetAddress> {
  //定义一个变量
  String _ads = '';
  
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Scaffold(
        appBar: AppBar(title: Text('获取收获地址'),),
        body: Center(
          child: Column(
            //垂直居中
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              RaisedButton(
                //按钮主题
                textTheme: ButtonTextTheme.primary,
                color: Theme.of(context).accentColor,
                child: Text('选择收货地址'),
                //点击
                onPressed: () async {
                    //通过路由跳转从子页面中传递过来的数据,都是异步的
                    var ads = await Navigator.of(context).push(
                      MaterialPageRoute(
                        builder: (BuildContext context){
                          return AddressList();
                        }
                      )
                    );
                    setState(() {
                     _ads = ads; 
                    });
                },
              ),
              Text('${_ads==""?"未查到收货地址":_ads}')
            ],
          ),
        ),
      ),
    );
  }
}

использоватьonTapИспользуйте сразу после нажатияpopВернитесь на первую страницу и верните данные

AddressList.dartКод файла:

import 'package:flutter/material.dart';

class AddressList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("我的地址列表"),),
      body: ListView(
        padding: EdgeInsets.all(10),
        children: <Widget>[
          GestureDetector(
            onTap: (){
              //pop后面可以跟上参数
              Navigator.of(context).pop('北京');
            },
            //给子组件添加事件
            child: Container(
              decoration: BoxDecoration(
                border: Border.all(color: Colors.black26)
              ),
              child: ListTile(
                leading: Icon(
                  Icons.account_box,
                  color: Colors.blue,
                ),
                title: Text(
                  '北京',
                  maxLines: 1,
                  overflow: TextOverflow.ellipsis,
                ),
              ),
            ),
          ),
          //给控件中间加间隙
          SizedBox(height: 10),
          GestureDetector(
            onTap: (){
              //pop后面可以跟上参数
              Navigator.of(context).pop('河南');
            },
            //给子组件添加事件
            child: Container(
              decoration: BoxDecoration(
                border: Border.all(color: Colors.black26)
              ),
              child: ListTile(
                leading: Icon(
                  Icons.account_box,
                  color: Colors.blue,
                ),
                title: Text(
                  '河南',
                  maxLines: 1,
                  overflow: TextOverflow.ellipsis,
                ),
              ),
            ),
          ),
          //给控件中间加间隙
          SizedBox(height: 10),
          GestureDetector(
            onTap: (){
              //pop后面可以跟上参数
              Navigator.of(context).pop('上海');
            },
            //给子组件添加事件
            child: Container(
              decoration: BoxDecoration(
                border: Border.all(color: Colors.black26)
              ),
              child: ListTile(
                leading: Icon(
                  Icons.account_box,
                  color: Colors.blue,
                ),
                title: Text(
                  '上海',
                  maxLines: 1,
                  overflow: TextOverflow.ellipsis,
                ),
              ),
            ),
          )
        ],
      ),
    );
  }
}

именованная маршрутизация

Подобно маршрутизации в Vue

базовый прыжок

Создал несколько новых страницMain.dart,Page1.dart,Page1.dartа такжеPage3.dartдля тестирования

импортировать файл,
существуетmain.dartсерединаroutesПуть конфигурации в (должен быть настроен в main.dart)
bodyПерейдите на страницу, которую необходимо отобразить

main.dartКод файла:

import 'package:flutter/material.dart';
import './files/Page1.dart';
import './files/Page2.dart';
import './files/Page3.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("Route"),
        ),
        body: Main(),
      ),
      //定义路由
      routes: {
        //需要使用context指定上下文
        '/page1': (context) => Page1(),
        '/page2': (context) => Page2(),
        '/page3': (context) => Page3(),
      },
    );
  }
}

существуетMain.dartПропишите в файле две кнопки для прыжков (обратите внимание, что однаmain.dartодинMain.dart)

Main.dartКод файла:

import 'package:flutter/material.dart';

class Main extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: Column(
            children: <Widget>[
              //定义按钮
              RaisedButton(
                  child: Text("跳转到Page1"),
                  onPressed: () {
                    //需要使用pushNamed方法
                    Navigator.pushNamed(context, "/page1");
                  },
              ),
              SizedBox(height: 20),
              RaisedButton(
                  child: Text("跳转到Page2"),
                  onPressed: () {
                    Navigator.pushNamed(context, "/page2");
                  },
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Нажмите кнопку, чтобы перейти на указанную страницу,Page1.dart,Page2.dart,Page3.dartБазовая структура страницы, просто вставьте страницу, чтобы увидеть:

Page1.dartКод файла:

import 'package:flutter/material.dart';

class Page1 extends StatefulWidget {
  @override
  _Page1State createState() => _Page1State();
}
class _Page1State extends State<Page1> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Page1"),),
      body: Text("Page1",style: TextStyle(fontSize: 40),),
    );
  }
}

прыжок извлечения маршрута

Как правило, если мы используем именованную маршрутизацию вместо вышеуказанного метода, мы всеОтделить маршрутизацию

Оптимизируйте приведенный выше код:

создать новыйRoutes.dartФайл используется для хранения правил маршрутизации,

Routes.dartКод файла:

import 'package:flutter/material.dart';
//引入文件
import '../files/Main.dart';
import '../files//Page1.dart';
import '../files//Page2.dart';
import '../files//Page3.dart';

//配置路由规则
final routes = {
  '/': (context) => Main(),
  '/page1': (context) => Page1(),
  '/page2': (context) => Page2(),
  '/page3': (context) => Page3(),
};

// 如果你要把路由抽离出去,必须写下面这一堆的代码,不用理解什么意思
var onGenerateRoute = (RouteSettings settings) {
  // 统一处理
  final String name = settings.name;
  final Function pageContentBuilder = routes[name];
  if (pageContentBuilder != null) {
    if (settings.arguments != null) {
      final Route route = MaterialPageRoute(
          builder: (context) =>
              pageContentBuilder(context, arguments: settings.arguments));
      return route;
    } else {
      final Route route =
          MaterialPageRoute(builder: (context) => pageContentBuilder(context));
      return route;
    }
  }
};

затем вmain.dartКонфигурация в файле использует:

import 'package:flutter/material.dart';
//引入Routes.dart文件
import './routes/Routes.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      initialRoute: '/',  //配置默认访问路径
      onGenerateRoute:onGenerateRoute,  //必须加上这一行,固定写法
    );
  }
}

После завершения настройки никакие другие места не нужно перемещать, чтобы реализовать наше извлечение маршрута.

прыжок по значению

Сразу после приведенного выше кода, когда мы используем именованную маршрутизацию и переходим после извлечения маршрута, мы хотим передать ему значение при переходе, так что же нам делать? очень простой

Измените приведенный выше код на основе

ИзменятьMain.dartМетод кнопки в файле при переходе передает значение следующим образом:

Вставьте только вторую кнопку перехода, никакой другой код перемещать не нужно

RaisedButton(
	  child: Text("跳转到Page2"),
	  onPressed: () {
		Navigator.pushNamed(context, "/page2",arguments: {
		  "id":102
		});
	  },
  ),

затем вRoutes.dartизменение в файлеpage2Правила маршрутизации:

'/page2': (context,{arguments}) => Page2(arguments:arguments),

Наконец вPage2.dartстраницаопределение переменных, рефакторинг, чтобы получить переданное значение:

import 'package:flutter/material.dart';

class Page2 extends StatefulWidget {
  //定义一个变量
  final arguments;
  //重构
  Page2({this.arguments});
  
  @override
  _Page2State createState() => _Page2State();
}

class _Page2State extends State<Page2> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Page2"),),
      //使用传递过来的值
      body: Text("${widget.arguments['id']}",style: TextStyle(fontSize: 40),),
    );
  }
}

исходный код

Нажмите -->Адрес источника


@_@