Всем привет, добро пожаловать на мой очередной урок. Сегодня у меня есть другая тема, которой я могу поделиться с вами. Как вы знаете, в моем предыдущем уроке я всегда делился с вами информацией о Riverpod. Итак, что я хотел бы сказать вам сегодня? Во Flutter иногда нам нужно мощное управление навигацией, которое мы можем использовать в нашем проекте Flutter. Один из замечательных пакетов, который Flutter должен оптимизировать наше управление навигацией, — это go_router.

Что такое go_router?

Пакет декларативной маршрутизации для Flutter, который использует Router API для предоставления удобного API на основе URL для навигации между различными экранами. Вы можете определять шаблоны URL-адресов, осуществлять навигацию с использованием URL-адресов, обрабатывать глубокие ссылки и ряд других сценариев, связанных с навигацией.

У go_router есть много преимуществ, позволяющих упростить навигацию:

Анализ пути и параметров запроса с использованием синтаксиса шаблона (например, «user/:id»)

Отображение нескольких экранов для пункта назначения (подмаршрутов)

Поддержка перенаправления — вы можете перенаправить пользователя на другой URL-адрес в зависимости от состояния приложения, например, на вход, когда пользователь не прошел проверку подлинности.

Поддержка нескольких навигаторов через ShellRoute — вы можете отобразить внутренний навигатор, который отображает свои страницы на основе согласованного маршрута. Например, чтобы отобразить BottomNavigationBar, который остается видимым в нижней части экрана.

Поддержка приложений Material и Cupertino.

Обратная совместимость с Navigator API

go_router похож на другое управление навигацией, но более мощное. В go_router мы можем передавать данные, используя свойство extra, которое нам предоставил go_router. К сожалению, go_router не поддерживает передачу нескольких данных.

Как вы можете видеть выше, go_router просто предоставляет нам возможность передать один объект. Существует проблема. Однако иногда в нашей разработке мы не просто передаем одни данные, вместо этого нам нужно передать 2 данных, 3 данных, 4 данных и т. д. Итак, как мы можем передать несколько данных с помощью go_router?

Хорошо, во-первых, давайте создадим проект.

import 'package:flutter/material.dart';
import 'package:go_router_example/routes/routing.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerConfig: appRouter,
    );
  }
}

Над моим main.dart. Достаточно просто, не так ли?

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

class MyFirstScreen extends StatelessWidget {
  const MyFirstScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('My First Screen'),
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Center(
            child: ElevatedButton(
                onPressed: () {
                  context.push('/second-screen');
                },
                style: ButtonStyle(
                    fixedSize: MaterialStateProperty.all(
                        Size(MediaQuery.of(context).size.width - 50, 50))),
                child: const Text('Navigate To Secon Screen')),
          ),
        ],
      ),
    );
  }
}

Я создал my_first_screen.dart. В MyFirstScreen я просто создаю кнопку, которую мы будем использовать для перехода на другие страницы, скажем, MySecondScreen.

Затем давайте создадим файл дротика с именем my_second_screen.dart. В MySecondScreen мы будем передавать данные с помощью конструктора.

import 'package:flutter/material.dart';

class MySecondScreen extends StatelessWidget {
  final String name;
  final int age;
  final String job;
  const MySecondScreen(
      {super.key, required this.name, required this.age, required this.job});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('My Second Screen'),
      ),
      body: Center(
        child: Column(
          children: [
            Text(
              'My name is $name',
              style: const TextStyle(
                fontSize: 18,
              ),
            ),
            Text(
              'My age is $age',
              style: const TextStyle(
                fontSize: 18,
              ),
            ),
            Text(
              'My job is $job',
              style: const TextStyle(
                fontSize: 18,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

В нашем routing.dart мы получили ошибки. Потому что мы просто передали данные конструктором.

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:go_router_example/screen_1.dart';
import 'package:go_router_example/screen_2.dart';

final GoRouter appRouter = GoRouter(
  routes: <RouteBase>[
    GoRoute(
      path: '/',
      builder: (BuildContext context, GoRouterState state) {
        return const MyFirstScreen();
      },
      routes: <RouteBase>[
        GoRoute(
          path: 'second-screen',
          builder: (BuildContext context, GoRouterState state) {
            return  MySecondScreen(
              age: ,
              job: ,
              name: ,
            );
          },
        ),
      ],
    ),
  ],
);

Да, как вы можете видеть выше, нам нужно передать данные требований (возраст, должность и имя). Для этого мы можем использовать функции, которые предоставил go_router. Мы можем указать (GoRouterState) для обработки данных требований. Я изменю свой файл routing.dart.

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:go_router_example/screen_1.dart';
import 'package:go_router_example/screen_2.dart';

final GoRouter appRouter = GoRouter(
  routes: <RouteBase>[
    GoRoute(
      path: '/',
      builder: (BuildContext context, GoRouterState state) {
        return const MyFirstScreen();
      },
      routes: <RouteBase>[
        GoRoute(
          path: 'second-screen',
          builder: (BuildContext context, GoRouterState state) {
            Map<String, dynamic> data = state.extra as Map<String, dynamic>;
            return MySecondScreen(
              age: data['age'],
              job: data['job'],
              name: data['name'],
            );
          },
        ),
      ],
    ),
  ],
);

Выше я изменил свой файл routing.dart. Как видите, я только что преобразовал state.extra в Map. Без приведения state.extra мы получим ошибку. Потому что state.extra, который нам предоставил go_router, относится к типу Object. Итак, нам нужно разобрать тип объекта на Map.

Хорошо, давайте перейдем к нашему MyFirstScreen.

Map<String, dynamic> data = {
                    'age': 10,
                    'job': 'Flutter Developer',
                    'name': 'John',
                  };
                  context.push('/second-screen', extra: data);

Я добавил данные в метод onPressed. Мы просто передаем данные как Map. Зачем нам нужно передавать данные как карту? Как вы знаете, в go_router мы не можем передавать несколько данных, потому что go_router поддерживает только одиночные данные (объект).

Итак, наш MyFirstScreen хотел бы,

Потрясающий! Наконец, мы решили одну из проблем с go_router. Надеюсь, вы, ребята, могли понять то, чем я делюсь с вами. Если у вас есть какие-либо вопросы, пожалуйста, сообщите мне ниже. Хорошо, спасибо за чтение, увидимся на следующем уроке!