Flutter не может изменить маршрут, потому что неопределенный контекст имени с PopupMenuButton, как решить? - PullRequest
0 голосов
/ 21 февраля 2019

Я хочу щелкнуть пункт меню (PopupMenuItem) и перейти к другому маршруту, используя Navigator.push, но контекст не определен внутри метода.

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {

  final List<Choice> choices = const <Choice>[
    const Choice(title: 'Settings', icon: Icons.settings),
    const Choice(title: 'Log out', icon: Icons.exit_to_app),
    ];



  @override
  Widget build(BuildContext context) {
    final title = 'MyTitle';

    return MaterialApp(
      title: title,
      home: Scaffold(
        appBar: AppBar(
          title: Text(title),
          actions: <Widget>[
                PopupMenuButton<Choice>(
                  onSelected: onItemMenuPress,
                  itemBuilder: (BuildContext context) {
                    return choices.map((Choice choice) {
                      return PopupMenuItem<Choice>(
                          value: choice,
                          child: Row(
                            children: <Widget>[
                              Icon(
                                choice.icon,
                              ),
                              Container(
                                width: 10.0,
                              ),
                              Text(
                                choice.title,
                              ),
                            ],
                          ));
                    }).toList();
                  },
                ),
              ],
        ),
        body: Text("Hello world")
      ),
    );

  }

    void onItemMenuPress(Choice choice) {   
      if (choice.title == 'Log out') {
        print("Logout");
        Navigator.push(context, MaterialPageRoute(builder: (context) => LogoutRoute()));
      } 
  }

}

class Choice {
  const Choice({this.title, this.icon});

  final String title;
  final IconData icon;
}

class LogoutRoute extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Logout"),
      ),
      body: Center(
        child: Text("Screen"),
      ),
    );
  }
}

Я попытался передать контекст в onItemMenuPress в этомспособ:

void onItemMenuPress(Choice choice, BuildContext context)

, но:

onSelected: onItemMenuPress(context)

не работает.

Ни один из этих подходов не работает:

onSelected: (Choice c) { Navigator.push(context, MaterialPageRoute(builder: (context) => LogoutRoute())); }

Я следовал этомуучебник: https://medium.com/flutter-community/building-a-chat-app-with-flutter-and-firebase-from-scratch-9eaa7f41782e

и есть фрагмент его кода (похожий на мой), который, кажется, работает для него: https://github.com/duytq94/flutter-chat-demo/blob/master/lib/main.dart

Я ссылаюсь на строку 235 (onSelected) и строки199-205 (фактический метод onItemMenuPress)

Как это возможно?Как я могу бальзам?Спасибо

1 Ответ

0 голосов
/ 21 февраля 2019

Здесь у вас есть:

MyApp    <------ context
  --> MaterialApp
   (--> Navigator built within MaterialApp)
      --> Scaffold
        --> App Bar
          --> ...

Поэтому, когда вы используете контекст для поиска Навигатора, вы используете контекст для MyApp, который не находится под навигатором.так что мы можем либо создать новый подкласс виджетов без состояний или состояний, чтобы он содержал ваш Scaffold, так как функция сборки в них вместо этого будет указывать на этот уровень, либо мы можем использовать Builder и определить обратный вызов компоновщика (который имеет контекстуказывая на Строителя), чтобы вернуть Scaffold.

Рабочий код, который мы создали, новый подкласс - HomeScreen:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final title = 'MyTitle';
    return MaterialApp(
      title: title,
      home: HomeScreen(title),
    );
  }
}

class HomeScreen extends StatelessWidget {
  final String title;

  HomeScreen(this.title);

  final List<Choice> choices = const <Choice>[
    const Choice(title: 'Settings', icon: Icons.settings),
    const Choice(title: 'Log out', icon: Icons.exit_to_app),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(title),
          actions: <Widget>[
            PopupMenuButton<Choice>(
              onSelected: (val) => onItemMenuPress(val, context),
              itemBuilder: (BuildContext context) {
                return choices.map((Choice choice) {
                  return PopupMenuItem<Choice>(
                      value: choice,
                      child: Row(
                        children: <Widget>[
                          Icon(
                            choice.icon,
                          ),
                          Container(
                            width: 10.0,
                          ),
                          Text(
                            choice.title,
                          ),
                        ],
                      ));
                }).toList();
              },
            ),
          ],
        ),
        body: Text("Hello world"));
  }

  void onItemMenuPress(Choice choice, BuildContext context) {
    if (choice.title == 'Log out') {
      print("Logout");
      Navigator.push(
          context, MaterialPageRoute(builder: (context) => LogoutRoute()));
    }
  }
}

class Choice {
  const Choice({this.title, this.icon});

  final String title;
  final IconData icon;
}

class LogoutRoute extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Logout"),
      ),
      body: Center(
        child: Text("Screen"),
      ),
    );
  }
}
...