Flutter не может изменить маршрут, потому что контекст неопределенного имени с PopupMenuButton, как решить?

Я хочу щелкнуть меню элемента (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)

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


person Francesco Romano    schedule 21.02.2019    source источник


Ответы (2)


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

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

Поэтому, когда вы используете контекст для поиска навигатора, вы используете контекст для MyApp, который не находится под навигатором. поэтому мы можем либо создать новый подкласс Stateless или Stateful Widget, который будет содержать ваш Scaffold, поскольку функция сборки внутри них будет указывать на этот уровень, либо мы можем использовать Builder и определить обратный вызов построителя (который имеет контекст, указывающий на 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"),
      ),
    );
  }
}
person anmol.majhail    schedule 21.02.2019

Это происходит из-за того, что ваш SDK флаттера и темный SDK не работают должным образом. вы можете решить эту проблему, обновив flutter sdk. перейдите в терминал и введите

флаттер апгрейд - сила

после этого ваши fluter sdk и dark sdk будут обновлены, после завершения установки все будет в порядке.

person Malith Ileperuma    schedule 04.02.2020