Is there a way to have an argument with two types in Dart?
Solution 1
Since you are expecting one of multiple types, what about having dynamic
and then in the push method of NavTo, you could check the type:
class NavTo {
dynamic route;
push(BuildContext context) {
if (route is String) {
...
} else if (route is Widget) {
...
}
}
}
Solution 2
I don’t believe the union type is available in Dart. I like your solution over the use of dynamic as it is strongly typed. You could use named parameters.
NavTo({this.route,this.widget})
But then you don’t have compile-type checking for one and only one parameter.
The only improvement I would make to your constructors is to add @required
.
Solution 3
Personnally i like to give Items a MaterialPageRoute params
static Widget simpleNavRow(String text, BuildContext context, MaterialPageRoute route) {
return Column(
children: <Widget>[
ListTile(
title: Text(text),
onTap: () {
Navigator.push(context, route);
},
),
Divider(),
],);
}
items stays dumb like this and i decide what they do in the parent. After you can create an item factory for each type you have that initialize the correct route like this :
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(),
],);
}
}
GoldenJoe
Updated on June 05, 2022Comments
-
GoldenJoe almost 2 years
For navigation, I built a simple factory class that generates a ListTile that pushes a route to the Navigator:
static Widget simpleNavRow(String text, BuildContext context, String route) { return Column( children: <Widget>[ ListTile( title: Text(text), onTap: () { Navigator.pushNamed(context, route); }, ), Divider(), ], ); }
However, I soon realized that it would be convenient to support pushing widgets as well (or instantiate from their class if possible). I couldn't figure out how to make the "route" argument accept either a String or a Widget, so I created a class that initializes with one of those two types. This code works, but is there a better way to achieve this?
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()))
-
graphicbeacon over 5 yearsTo extend my answer, you are looking for a union type. Some research brought me across this solution by Tobe and this article. Hope these help inform how you proceed.
-
GoldenJoe over 5 yearsThanks. Wasn't sure what it's called. Since it isn't supported by the language, I'll probably just stick to the current solution. A whole library just for this is overkill.