Навигационный ящик не работает для экрана внутри экрана - PullRequest
0 голосов
/ 05 февраля 2019

Я хочу сохранить Навигационный ящик на всех экранах.Были вопросы по стеку по этому вопросу, но мой вопрос немного отличается, например, Сохранение Ящика AppBar на всех страницах.При нажатии A в навигационном ящике открывается экран A и, соответственно, то же самое для B и C. Теперь на экране C есть кнопка, и при нажатии этой кнопки я собираюсь перейти к экрану D, теперь на экране D отображается значок навигационного окна.ящик никогда не открывается.Я попытался напечатать инструкцию в методе, где вызывается ящик, и оператор печати печатает, но ящик никогда не открывается.Ниже приведен мой код

У меня есть базовый класс, ящик которого выглядит следующим образом:

 class BaseScreen extends StatefulWidget {
  final List<Menu> menuList;
  final String userType;
  final String userId;

  const BaseScreen({Key key, this.menuList, this.userType, this.userId})
      : super(key: key);

  @override
  BaseScreenState createState() {
    return new BaseScreenState();
  }
}

class BaseScreenState extends State<BaseScreen> {
  String screenNameSelected = "A";

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: <Widget>[
          _getDrawerItemWidget(screenNameSelected),

        ],
      ),
      drawer: SizedBox(
        width: 100,
        child: Drawer(
          child: ListView.separated(
            separatorBuilder: (context, index) => Material(
                  elevation: 2,
                  shadowColor: shadow,
                  child: Divider(
                    color: white,
                  ),
                ),
            itemBuilder: (BuildContext context, int index) {
              return ListTile(
                onTap: () {
                  openScreen(
                      widget.menuList[index].title,
                      widget.userId,
                      MenuList.returnLoginType(widget.userType).toString(),
                      context);
                  Navigator.pop(context);
                },
                title: Padding(
                  padding: const EdgeInsets.only(top: 8),
                  child: Image.asset(
                    widget.menuList[index].image,
                    width: 35,
                    height: 35,
                  ),
                ),

              );
            },
            itemCount: widget.menuList?.length ?? 0,
            shrinkWrap: true,
            physics: BouncingScrollPhysics(),
          ),
        ),
      ),
    );
  }

  _getDrawerItemWidget(String selectedScreenName) {
    switch (selectedScreenName) {
      case A:
        return A();
      case B:
        return B();
      case C:
        return C();

      default:
        return Container();
    }
  }

  void openScreen(String screenName, String userId, String loginType,
      BuildContext context) {
    if (screenName.toLowerCase() == "A".toLowerCase()) {
      setState(() {
        screenNameSelected = "A";
      });
    } else if (screenName.toLowerCase() == "B".toLowerCase()) {
      setState(() {
        screenNameSelected = "B";
      });
    } else if (screenName.toLowerCase() == "C".toLowerCase()) {
      setState(() {
        screenNameSelected = "C";
      });
    }

  }

}

Я создал пользовательский класс для панели приложения, поскольку панель приложения сильно настроена

class CustomAppBar extends StatelessWidget {
  final String subTitleText;
  final String subTitleImage;

  const CustomAppBar(
      {Key key, @required this.subTitleText, @required this.subTitleImage})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        SafeArea(
          child: Column(
            children: <Widget>[
              Builder(builder: (context) => customAppBar(context)),
              SizedBox(
                height: 5.0,
              ),
              subTitleRow(
                subTitleText,
                subTitleImage,
              )
            ],
          ),
        ),

      ],
    );
  }
}

Widget subTitleRow(String subtitleText, String subtitleImage) {
.........
}


Widget customAppBar(BuildContext context) {
  return Material(
    elevation: 5.0,
    shadowColor: shadow,
    child: SafeArea(
      child: Stack(
        children: <Widget>[
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            mainAxisSize: MainAxisSize.max,
            children: <Widget>[
              Image.asset(
                "images/toolbar_logo.webp",
                width: 80,
                height: 50,
              ),
            ],
          ),
          IconButton(
            icon: Image.asset("images/menu.webp"),
            onPressed: () {
              Scaffold.of(context).openDrawer();
            },
            iconSize: 20,
          ),
        ],
      ),
    ),
  );
}

Теперь у моих классов A, B и C нет строительных лесов, но я предоставил своему классу D строительные леса, и я думаю, что это является причиной проблемы.Отсутствие класса D с помостом не дает правильной компоновки

Код для классов A, B и C выглядит следующим образом

class A extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ShortBioProvider(
      child:  Column(
            children: <Widget>[
              CustomAppBar(
                subTitleImage: "images/settings.webp",
                subTitleText: SETTINGS.toUpperCase(),
              ),
              SizedBox(
                height: 20,
              ),
              SettingsList(),
            ],
          ),

    );
  }
}

B и C очень похожи на A.

Теперь для кода класса D

class D extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(body: Column(children: <Widget>[
      CustomAppBar(
        subTitleImage: "images/settings.webp",
        subTitleText: D.toUpperCase(),
      ),
      SizedBox(
        height: 20,
      ),
      ........
    ],),);
  }
}

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

1 Ответ

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

Ах, теперь, когда вы добавили свой код, это имеет смысл.

То, что происходит в том случае, когда в случае D у вас есть два разных скаффолда:

BaseScreenState
--> Scaffold 1
    -->  drawer
         body
           --> stack
             --> D
               --> Scaffold 2
                 -->CustomAppBar ....

Когда вы делаете Scaffold.of(контекст), он просматривает дерево, чтобы найти ближайший эшафот, который в данном случае оказывается Scaffold 2, у которого нет выдвижного ящика.Эшафот в вашем классе D, похоже, ничего не делает, поэтому удаление его должно решить вашу проблему.

ОДНАКО

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

Вместо этого вам следует создать страницу, которая включает в себя помост, ящик, приложениепанель и т. д. для каждой страницы вашего приложения, а затем переключайтесь между ними с помощью навигатора.(Обратите внимание, что если вы создаете виджет для каждой страницы, это не означает, что компоненты не могут быть общими). ​​

Архитектура, которая имеет смысл во флаттере, выглядит следующим образом:

  • Виджет Stateful верхнего уровня (с сохранением состояния лучше подходит для горячей перезагрузки, вид без состояния может вызвать проблемы), что-то вроде MyApp (но измените My на имя фактического приложения).
  • вФункция построения, это делает MaterialApp.Вы могли бы потенциально поместить логику для построения различных страниц в материале приложения onGenerateRoute - я считаю, что это может сделать его чище и проще, чтобы понять, что происходит, чем строить вещи на лету.
  • если вы переходите между страницами по имени (строке), вы должны преобразовать имена в глобальные константы.
  • Виджет с отслеживанием состояния или без сохранения состояния для каждой страницы (если страницы не достаточно похожи, чтобыразличаются несколькими простыми параметрами), который в функции сборки создаст каркас, панель приложения, навигационный ящик и т. д.
  • , опционально каркас может быть также собственным виджетом
  • виджет дляпанель вашего приложения (то есть CustomAppBar)
  • Виджет для вашего навигационного ящика

Несколько других вещей, на которые стоит обратить внимание:

  1. Разделение объектов при сборкефункция, а не класс, кажется, может быть быстрее, но это не так.Наличие двух и многих виджетов в одной функции сборки (и не обманывайте себя, вызов функции, которая возвращает виджет из функции сборки, аналогичен размещению кода непосредственно в функции для повышения производительности), на самом деле может означать больше вычислений длятрепетать, так как каждый раз, когда необходимо перестроить виджет, нужно собирать и проверять весь набор классов, тогда как, если вы используете правильную инкапсуляцию в виджетах, большую часть работы можно пропустить, если ничего не изменится в этой части дерева виджетов.
  2. Может показаться, что создание Scaffold, AppBar и Drawer на каждой странице расточительно.Однако из-за того, как флаттер кеширует вещи и разумно сканирует дерево виджетов, он на самом деле довольно производительный, и именно поэтому команда флаттеров рекомендует что-то делать.
  3. Всегда выясняйте, из какого контекста сборки вы вызываете вещи, тогдаВы можете следить за деревом сборки, чтобы выяснить, какой виджет действительно вызывается при вызове .of (context).

Надеюсь, это поможет!

...