Search code examples
flutterclasswidgetinstance

I have a widget that I want to use in multiple routes. I need this widget to use different custom class instances depending on which route it is


The widget always uses the instance which is in it's own dart file. I want to create different instances on each route and have the widget use that exact instance.

My custom class (I only need the name right now):

class Chat {
String name, lastMesssage, image, time, page;
bool isActive;

Chat ({
  this.name,
  this.lastMesssage,
  this.image,
  this.time,
  this.isActive,
  this.page,
});
}

My widget:

Chat chat;

class Bar extends StatefulWidget {
  @override
  _BarState createState() => _BarState();
}

class _BarState extends State<Bar> {
  @override
  Widget build(BuildContext context) {
    return  Row(
      children: [
        SizedBox(width: 15,),
        Image(image: AssetImage("assets/asset.png"), width: 55, height: 55,),
        SizedBox(width: 10,),
        Column(
          children: [
            //that's where I need different Chat instances
            Text(chat.name, style: TextStyle(
              color: Colors.black,
              fontSize: 25,
            ),),
            Text("Online", style: TextStyle(
              color: Colors.grey[600],
              fontSize: 15,
            ),),
          ],
        ),
        SizedBox(height: 0,width: 85,),
        Icon(Icons.call_rounded, color: Colors.blueGrey, size: 45, ),
        SizedBox(height:0, width: 14),
        Icon(Icons.videocam, color: Colors.blueGrey, size: 45, ),
      ],
    );
  }
}

Where I need the widget (I want Bar() to use michael scott inside it, for instance):

Chat chat = Chat(name: michael scott);

return Scaffold(
      backgroundColor: Colors.grey[200],
      body: Column(
        children: [
          SizedBox(height: 30,),
          Bar(), 
          //It goes on

Solution

  • You have to pass that exact Chat instance when navigation to the Bar route. In that case, you have to options.

    1. Taking the Chat argument in the Bar constuctor

    class Bar extends StatefulWidget {
      final Chat chat;
    
      const Bar({Key? key, required this.chat}) : super(key: key);
      @override
      _BarState createState() => _BarState();
    }
    
    class _BarState extends State<Bar> {
      @override
      Widget build(BuildContext context) {
        return Row(
          children: [
            SizedBox(
              width: 15,
            ),
            Image(
              image: AssetImage("assets/asset.png"),
              width: 55,
              height: 55,
            ),
            SizedBox(
              width: 10,
            ),
            Column(
              children: [
                //that's where I need different Chat instances
                Text(
                  chat.name,
                  style: TextStyle(
                    color: Colors.black,
                    fontSize: 25,
                  ),
                ),
                Text(
                  "Online",
                  style: TextStyle(
                    color: Colors.grey[600],
                    fontSize: 15,
                  ),
                ),
              ],
            ),
            SizedBox(
              height: 0,
              width: 85,
            ),
            Icon(
              Icons.call_rounded,
              color: Colors.blueGrey,
              size: 45,
            ),
            SizedBox(height: 0, width: 14),
            Icon(
              Icons.videocam,
              color: Colors.blueGrey,
              size: 45,
            ),
          ],
        );
      }
    }
    

    Then you can create an instance of Bar with a specific Chat instance, like this:

    Bar(
      chat: Chat(
        //Fill the rest of the properties
      ),
    ),
    

    If you want to navigate to another route with this Bar instance, you will use the following:

    Navigator.of(context).push(
      MaterialPageRoute(builder: (context) => Bar(chat: Chat())),
    ),
    

    2. Passing the chat argument with named route

    In this case we don't take the argument from the contractor, we use the following method from the Navigator class instead:

    Navigator.of(context).pushNamed('/bar', arguments: Chat());
    

    In order to this method work properly, we should also add the onGenerateRoute callback to the MaterialApp in the root of the application. Like this:

     MaterialPageRoute? onGenerateRoute(RouteSettings settings) {
      if (settings.name == '/bar') {
        return MaterialPageRoute(builder: (context) => Bar(), settings: settings);
      }
    }
    
    MaterialApp(
      onGenerateRoute: onGenerateRoute,
    )
    

    After navigating to the Bar, we have to retrieve the arguments that are passed to the route. Usually this is done in the first line of the build method of the widget. In this case, the Bar widget will look like this:

    class Bar extends StatefulWidget {
      const Bar({Key? key,}) : super(key: key);
      @override
      _BarState createState() => _BarState();
    }
    
    class _BarState extends State<Bar> {
      @override
      Widget build(BuildContext context) {
        final chat = ModalRoute.of(context)?.settings.arguments as Chat;
        return Row(
          children: [
            SizedBox(
              width: 15,
            ),
            Image(
              image: AssetImage("assets/asset.png"),
              width: 55,
              height: 55,
            ),
            SizedBox(
              width: 10,
            ),
            Column(
              children: [
                //that's where I need different Chat instances
                Text(
                  chat.name,
                  style: TextStyle(
                    color: Colors.black,
                    fontSize: 25,
                  ),
                ),
                Text(
                  "Online",
                  style: TextStyle(
                    color: Colors.grey[600],
                    fontSize: 15,
                  ),
                ),
              ],
            ),
            SizedBox(
              height: 0,
              width: 85,
            ),
            Icon(
              Icons.call_rounded,
              color: Colors.blueGrey,
              size: 45,
            ),
            SizedBox(height: 0, width: 14),
            Icon(
              Icons.videocam,
              color: Colors.blueGrey,
              size: 45,
            ),
          ],
        );
      }
    }