How passing widget dynamically in class constructor parameter

6,040

Solution 1

I think you want display to be a builder function that returns a MyTextWidget.

import 'package:flutter/material.dart';

Future<void> main() async {
  return runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(final BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(final BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Home")),
      body: Center(
        child: Example(
          display: ({@required final String text}) {
            assert(text != null);
            return MyTextWidget(text: text);
          },
          text: "some text",
        ),
      ),
    );
  }
}

class MyTextWidget extends StatelessWidget {
  final String text;

  MyTextWidget({@required this.text}) : assert(text != null);

  @override
  Widget build(final BuildContext context) {
    return Text(this.text);
  }
}

typedef Widget DisplayType({@required final String text});

class Example extends StatefulWidget {
  final DisplayType display;
  final String text;

  Example({
    @required this.display,
    @required this.text,
  })  : assert(display != null),
        assert(text != null);

  @override
  State<StatefulWidget> createState() {
    return ExampleState();
  }
}

class ExampleState extends State<Example> {
  @override
  Widget build(final BuildContext context) {
    return this.widget.display(text: this.widget.text);
  }
}

Solution 2

You don't need to pass the down the widget, just import it in the class that you want to use it.

When you want to instantiate it, you need to use parenthesis MyTextWidget().

You don't need to use this when calling the parameters passed to a Stateful Widget, just widget.text will work.

You seem to be having some misunderstandings about Flutter. There are very rare occasions where you need to use this.

Share:
6,040
Ali.Sh
Author by

Ali.Sh

Updated on December 17, 2022

Comments

  • Ali.Sh
    Ali.Sh over 1 year

    This is my first question in Stackoverflow. I'm trying to call a widget in another StatefulWidget when we passing it as class constuctor parameter.

    So i have this custom widget :

    class MyTextWidget extends StatelessWidget {
    
      final String text;
    
      MyTextWidget({ @required this.text });
    
      @override
      Widget build(BuildContext context) {
        return Text(this.text);
      }
    
    }
    

    i want to use in another widget like this (with pass in class constructor parameter)

    import 'package:myproject/MyTextWidget.dart';
    .
    .
    .
    // Passing widget like this
    child: Example(display: MyTextWidget,text: this.widget.text);
    .
    .
    .
    // And use this widget like this
    this.widget.display(text: this.widget.text);
    

    this is my first code :

    class Example extends StatefulWidget {
    
      final Widget display;
      final String text;
    
      Example({ @required this.display, @required this.text });
    
      @override
      State<StatefulWidget> createState() {
        return ExampleState();
      }
    
    }
    
    class ExampleState extends State<Example> {
    
      @override
      Widget build(BuildContext context) {
          return this.widget.display(text: this.widget.text); // here we have error
      }
    
    }
    

    but i have this error

    The expression doesn't evaluate to a function, so it can't be invoked.dart(invocation_of_non_function_expression)
    

    I realize i need to make a typedef for this problem so i improve code like this:

    typedef Widget DisplayType({ @required String text });
    
    class Example extends StatefulWidget {
    
      final DisplayType display;
      final String text;
    
      Example({ @required this.display, @required this.text });
    
      @override
      State<StatefulWidget> createState() {
        return ExampleState();
      }
    
    }
    
    class ExampleState extends State<Example> {
    
      @override
      Widget build(BuildContext context) {
          return this.widget.display(text: this.widget.text);
      }
    
    }
    

    Our error is fixed but when i want to pass MyTextWidget in another widget:

    child: Example(display: MyTextWidget,text: this.widget.text);
    
    

    Finally i get this error:

    The argument type 'Type' can't be assigned to the parameter type 'Widget Function({String text})'.dart(argument_type_not_assignable)
    
    

    how can i fix this problem?

    • J. S.
      J. S. about 4 years
      You don't need to pass the down the widget, just import it in the class that you want to use it.
  • Ali.Sh
    Ali.Sh about 4 years
    about "import": i know i can simply import my widget but i want make many custom widget and make this dynamically for example if user is admin or customer or some condition. I can change my code like you say but i'm Curious how imposible this. about "this": I use it for better readability. Thanks.
  • Ted Henry
    Ted Henry about 4 years
    "There are very rare occasions where you need to use this." I always write "this". It makes the code easier to read.
  • Ali.Sh
    Ali.Sh about 4 years
    Thank you Ted, this was exactly what I needed. Do you think this method has a negative effect on performance?
  • Ted Henry
    Ted Henry about 4 years
    I don't have any expectation that this will perform poorly.