Is there a way to have an argument with two types in Dart?

12,585

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

}
Share:
12,585
GoldenJoe
Author by

GoldenJoe

Updated on June 05, 2022

Comments

  • GoldenJoe
    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
    graphicbeacon over 5 years
    To 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
    GoldenJoe over 5 years
    Thanks. 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.