在Dart中有没有一种方法可以使用两种类型进行参数传递?

16

为了导航,我创建了一个简单的工厂类,用于生成一个ListTile,以向Navigator推送一个路由:

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

然而,我很快意识到支持推送widget(或尽可能从它们的类实例化)将是方便的。我无法弄清如何使“route”参数接受字符串或widget,因此创建了一个使用这两种类型之一初始化的类。这段代码可以工作,但是否有更好的方法来实现这个目的?

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()))

1
关于 MaterialApp#onGenerateRoute 怎么样?这样你就可以使用 pushNamed,同时仍然有自由返回任何你想要的 Route - pskink
在这个具体的实现中,我正在我的项目中设置一个游乐场来测试不同的小部件,因为我构建它们。每个组件都有自己的屏幕,但它并不重要到足以列在我的路由索引中。这就是为什么我只想推一个愚蠢的小部件。 - GoldenJoe
4个回答

16

由于您期望的是多种类型之一,那么考虑使用 dynamic,然后在 NavTo 的 push 方法中可以检查类型:

class NavTo {
  dynamic route;

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

1
为了扩展我的回答,您正在寻找一个联合类型。一些研究让我发现了Tobe的解决方案这篇文章。希望这些可以帮助您进一步了解如何处理。 - graphicbeacon
谢谢。我不确定它的叫法。由于语言不支持它,我可能只会坚持当前的解决方案。专门为此编写整个库有些大材小用。 - GoldenJoe
动态是太笼统了。如果我能像在PHP中那样说“狗|猫”就太好了。与使用接口或基类无关。 - undefined

3

我不认为Dart中有联合类型。我喜欢你的解决方案,因为它是强类型的,而不是使用dynamic。您可以使用命名参数。

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

但是这样你就无法对一个参数进行编译类型检查。

我对你的构造函数唯一的改进就是添加@required


1

个人喜欢为项目提供MaterialPageRoute参数

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

items保持不变,我在父级中决定它们的操作。之后,您可以为每个类型创建一个项目工厂,以此初始化正确的路由,如下所示:

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(),
    ],);
}

}

0
你为什么要在一个prop中使用不同的功能呢?没必要在一个函数中处理所有的事情,这违反了单一职责原则。你可以创建两个方法来实现这个功能。
class NavTo {
  String routeName;
  Widget widget;

  NavTo.routeName(this.routeName);
  NavTo.widget(this.widget);

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

  pushNamed(BuildContext context) {
    if (routeName != null) {
      Navigator.pushNamed(context, route);
    }
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接