Есть ли способ спорить с двумя типами в Dart?

Для навигации я создал простой фабричный класс, который генерирует ListTile, который подталкивает маршрут к навигатору:

static Widget simpleNavRow(String text, BuildContext context, String route) {
  return Column(
    children: <Widget>[
      ListTile(
        title: Text(text),
        onTap: () {
          Navigator.pushNamed(context, route);
        },
      ),
      Divider(),
    ],
  );
}

Однако вскоре я понял, что было бы удобно поддерживать и push-виджеты (или, если возможно, создавать экземпляры из их класса). Я не мог понять, как заставить аргумент «маршрут» принимать либо строку, либо виджет, поэтому я создал класс, который инициализируется одним из этих двух типов. Этот код работает, но есть ли лучший способ добиться этого?

class NavTo {
  String route;
  Widget widget;

  NavTo.route(this.route);
  NavTo.widget(this.widget);

  push(BuildContext context) {
    if (route != null) {
      Navigator.pushNamed(context, route);
    }
    if (widget != null) {
      Navigator.push(context, MaterialPageRoute(builder: (context) {
        return widget;
      }));
    }
  }
}

class ListHelper {
  static final padding = EdgeInsets.all(12.0);

  static Widget simpleNavRow(String text, BuildContext context, NavTo navTo) {
    return Column(
      children: <Widget>[
        ListTile(
          title: Text(text),
          onTap: () {
            navTo.push(context);
          },
        ),
        Divider(),
      ],
    );
  }
}

// usage:
// ListHelper.simpleNavRow('MyWidget', context, NavTo.widget(MyWidget()))

что насчет MaterialApp#onGenerateRoute? таким образом вы можете использовать pushNamed и по-прежнему иметь свободу возвращать любой Route, какой захотите.

pskink 10.11.2018 10:33

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

GoldenJoe 10.11.2018 22:29
Что такое компоненты React? Введение в компоненты | Типы компонентов
Что такое компоненты React? Введение в компоненты | Типы компонентов
Компонент - это независимый, многократно используемый фрагмент кода, который делит пользовательский интерфейс на более мелкие части. Например, если мы...
12
2
11 209
3

Ответы 3

Поскольку вы ожидаете один из нескольких типов, как насчет наличия dynamic, а затем в методе push NavTo, вы можете проверить тип:

class NavTo {
  dynamic route;

  push(BuildContext context) {
    if (route is String) {
       ...
    } else if (route is Widget) {
       ...
    }
  }
}

Чтобы расширить мой ответ, вы ищете тип союза. Некоторое исследование привело меня к этому решение от Tobe и эта статья. Надеюсь, они проинформируют вас о ваших дальнейших действиях.

graphicbeacon 10.11.2018 20:03

Спасибо. Не знал, как это называется. Поскольку это не поддерживается языком, я, вероятно, просто буду придерживаться текущего решения. Целая библиотека только для этого - это перебор.

GoldenJoe 10.11.2018 22:20

Я не верю, что тип профсоюзов доступен в Dart. Мне нравится ваше решение по сравнению с использованием dynamic, поскольку оно строго типизировано. Вы можете использовать именованные параметры.

NavTo({this.route,this.widget})

Но тогда у вас нет проверки типа компиляции для одного-единственного параметра.

Единственное улучшение, которое я бы внес в ваши конструкторы, - это добавить @required.

Лично мне нравится давать Items параметры MaterialPageRoute

static Widget simpleNavRow(String text, BuildContext context, MaterialPageRoute route) {
 return Column(
   children: <Widget>[
     ListTile(
      title: Text(text),
      onTap: () {
        Navigator.push(context, route);
      },
     ),
    Divider(),
  ],);
}

элементы остаются такими же тупыми, и я решаю, что они делают в родительском элементе. После того, как вы сможете создать фабрику элементов для каждого типа, вы инициализируете правильный маршрут следующим образом:

class ItemExemple extends StatelessWidget {

final String text;
final MaterialPageRoute route;

ItemExemple(this.text, this.route);

factory ItemExemple.typeA(String text, BuildContext context) =>
  new ItemExemple(text, new MaterialPageRoute(builder: (context) => new   ItemA()));

factory ItemExemple.typeB(String text, BuildContext context) =>
  new ItemExemple(text, new MaterialPageRoute(builder: (context) => new ItemB()));

@override
Widget build(BuildContext context) {
  return Column(
    children: <Widget>[
      ListTile(
        title: Text(this.text),
        onTap: () {
          Navigator.push(context, route);
        },
      ),
      Divider(),
    ],);
}

}

Другие вопросы по теме