Флаттер: как я могу перейти на страницу, которая уже находится в стеке навигатора? - PullRequest
1 голос
/ 09 октября 2019

У меня есть ящик с именованными маршрутами на разные страницы поиска. Нажав на маршрут, вы перейдете на страницу поиска. Каждый элемент на странице поиска переходит на страницу сведений. Кнопка «Назад» открывает страницу с подробностями, и я снова на странице поиска. Этот сценарий правильно использует стек навигатора.

Но как я могу переключаться между несколькими страницами поиска? Я могу открыть только одну страницу поиска, а затем нажать другую.

Другой вариант использования, который я ищу, - это переключение между страницами сведений. В этом случае Навигатор будет содержать (в этом порядке): первую страницу поиска, первую страницу подробностей, вторую страницу поиска, вторую страницу подробностей. Я хочу переключаться между двумя страницами сведений.

Есть ли способ заглянуть в стек Navigator и вывести заглядываемую запись на вершину стека?

Помогают ли здесь несколько навигаторов? Можно ли переключаться между навигаторами?

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

GlobalKey<NavigatorState> navKey = GlobalKey( );

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

class MyApp extends StatelessWidget {

    final Provider<MyMenu> menuProvider = Provider(
            builder: ( context ) => MyMenu( ) );

    @override
    Widget build( BuildContext context ) {
        return MultiProvider(
            child: MaterialApp(
                title: 'My App',
                home: MyHomePage( ),
                navigatorKey: navKey,
                routes: {
                    routePage1: ( context ) => Page1( ),
                    routePage2: ( context ) => Page2( ),
                },
                theme: ThemeData( primarySwatch: Colors.blue, ),
            ),
            providers: [
                menuProvider,
            ], );
    }
}

class MyMenu extends StatelessWidget {

    @override
    Widget build( BuildContext context ) {
        String currentRoute = getCurrentRouteName( );

        return Drawer( child: ListView( children: <Widget>[
            ListTile(
                leading: Icon( Icons.home ),
                onTap: ( ) => navigateTo( context, routePage1 ),
                selected: currentRoute == routePage1,
                title: Text( "Page 1" ),
            ),
            ListTile(
                onTap: ( ) => navigateTo( context, routePage1 ),
                selected: currentRoute == routePage1,
                title: Text( "Page 1" ),
            ),
            ListTile(
                onTap: ( ) => navigateTo( context, routePage2 ),
                selected: currentRoute == routePage2,
                title: Text( "Page 2" ),
            ),
        ],
        ),
        );
    }
}

String getCurrentRouteName( ) {
    String currentRouteName;
    navKey.currentState.popUntil( ( route ) {
        currentRouteName = route.settings.name;
        return true;
    } );
    return currentRouteName;
}

void navigateTo( BuildContext context, String namedRoute, { Object arguments } ) {
    // --- Close drawer menu if open
    if ( Scaffold
            .of( context )
            .isDrawerOpen ) {
        navKey.currentState.pop( );
    }

    // --- No navigation if target page already active
    String currentRoute = getCurrentRouteName( );
    if ( currentRoute == namedRoute ) return;

    // --- Navigate to target
    if ( currentRoute == "/" ) {
        navKey.currentState.pushNamed( namedRoute, arguments: arguments );
    } else {
        navKey.currentState.popAndPushNamed( namedRoute, arguments: arguments );
    }
}

class MyAppBar extends StatelessWidget implements PreferredSizeWidget {
    @override
    Widget build( BuildContext context ) {
        String currentRoute = getCurrentRouteName( );
        return AppBar(
            leading: MenuButton( ),
            title: Text( 'my app -> ${currentRoute}' ), );
    }

    @override
    Size get preferredSize => Size.fromHeight( kToolbarHeight );
}

class MenuButton extends StatelessWidget {
    @override
    Widget build( BuildContext context ) {
        return IconButton(
            icon: Icon( Icons.menu ),
            onPressed: ( ) {
                ScaffoldState scaffold = Scaffold.of( context );
                if ( scaffold.isDrawerOpen ) {
                    navKey.currentState.pop( );
                } else {
                    scaffold.openDrawer( );
                }
            },
        );
    }
}

class MyHomePage extends StatelessWidget {
    @override
    Widget build( BuildContext context ) {
        return Scaffold(
            appBar: MyAppBar( ),
            body: Center(
                child: Text( "This is the Homepage" ),
            ),
            drawer: Provider.of<MyMenu>( context ),
        );
    }
}

const String routePage1 = '/page1';

class Page1 extends StatelessWidget {
    @override
    Widget build( BuildContext context ) {
        return Scaffold(
            appBar: MyAppBar( ),
            body: Center(
                child: Text( "This is Page 1" ),
            ),
            drawer: Provider.of<MyMenu>( context ),
        );
    }
}

const String routePage2 = '/page2';

class Page2 extends StatelessWidget {
    @override
    Widget build( BuildContext context ) {
        return Scaffold(
            appBar: MyAppBar( ),
            body: Center(
                child: Text( "This is Page 2" ),
            ),
            drawer: Provider.of<MyMenu>( context ),
        );
    }
}

1 Ответ

0 голосов
/ 10 октября 2019

Создайте поле с типом Widget и замените эти виджеты в пункте меню, как показано ниже:

 enum DrawerSelection {
  home,
  cropFamilies,
  cropCalender,
  favorites,
  settings,
  notes,
  contactUs,
  disclaimer
 }

class _MyHomePage extends State<MyHomePage> {

DrawerSelection _drawerSelection = DrawerSelection.home;
Widget _appBarTitle = Text("Home");


Widget _currentWidget = MainWidget();

ListTile(
        selected: _drawerSelection == DrawerSelection.home,
        title: Text('Home'),
        leading: Icon(Icons.home),
        onTap: () {
          _drawerSelection = DrawerSelection.home;
          Navigator.pop(context);
          _currentWidget = MainWidget();
          setState(() {
            _appBarTitle = Text("Home");
          });
        },
      ),
  ListTile(
        selected: _drawerSelection == DrawerSelection.cropFamilies,
        title: Text('Crop families فصل کا خاندان'),
        leading: Icon(Icons.nature),
        onTap: () {
          _drawerSelection = DrawerSelection.cropFamilies;
          Navigator.pop(context);
          _currentWidget = CropFamiliesWidget();
          setState(() {
            _appBarTitle = Text("Crop families فصل کا خاندان");
          });
        },
      ),

Сделайте это во всех ваших пунктах меню. Вы можете игнорировать выбор ящика, если не хотите отображать выбранный цвет в меню ящика.

обновление Если вы хотите вернуться обратно в стек к нужному маршруту, вы можете сделать это с помощью popUntil. метод, как показано ниже. см. здесь

  Navigator.popUntil(context, ModalRoute.withName('/login'));
...