简体   繁体   中英

Flutter pass provider as an argument

I have a TemplateView page that has a content parameter that hosts content that changes depending on my application. Each content has a specific provider. On the other hand, my TemplateView page has a button which calls a validation function common to each provider.

Here the example of my app (in green my TemplateView, in red the content who change):

在此处输入图像描述

Here is a simplified code of Template View. We see the call to the content and the validation button which calls the provider of the content ContentView1.

class TemplateView extends StatelessWidget{
  final String title;
  final StatelessWidget content;
  TemplateView ({
        Key? key,
        required this.title,
        required this.content,
        required this.validationMessage,
      }) : super(key: key);

  @override
  Widget build(BuildContext context)
  {
    return GestureDetector(
      onTap: (() => FocusScope.of(context).requestFocus(FocusNode())),
      child: SafeArea(
        child: Scaffold(
          appBar: AppBar(
            title: Text(title),
          ),
          body : _buildBody(context),
        ),
      ),
    );
  }

  Widget _buildBody(BuildContext context)
  {
    // Here the call of my provider for the ContentView1
    var _messageProvider = Provider.of<ContentView1Provider>(context);

    return Column(
      children: [
        SingleChildScrollView(
          child: Container(
            child: content,
          ),
        ),
        InkWell(
            child: Container(
              child: Text('SAVE'),
            ),
            onTap: () => _messageProvider.validation()
        ),
      ],
    );
  }
}

And here, how I call the TemplateView in my router:

case RouterName.kContentView1:
  return CupertinoPageRoute(
      builder: (context) => ChangeNotifierProvider<ContentView1Provider>(
        create: (BuildContext context) => ContentView1Provider(),
        child: TemplateView(
            title: "Content 1 page",
            message: ContentView1(),
        ),
      )
  );

All are working, now like I said the contents will change but my TemplateView is common. I therefore cannot enter in the TemplateView the call to the provider directly since it will change depending on the pages.

So I want to make the call to the provider in the TemplateView settings but it doesn't work.

My new TemplateView:

class TemplateView extends StatelessWidget{
  final String title;
  final StatelessWidget content;
  final Function validationMessage; // => I added this line
  TemplateView({
        Key? key,
        required this.title,
        required this.content,
        required this.validationMessage, // => I added this line
      }) : super(key: key);

  @override
  Widget build(BuildContext context)
  {
    // => I remove the call of the provider line
    return GestureDetector(
      onTap: (() => FocusScope.of(context).requestFocus(FocusNode())),
      child: SafeArea(
        child: Scaffold(
          appBar: AppBar(
            title: Text(title),
          ),
          body : _buildBody(context),
        ),
      ),
    );
  }

  Widget _buildBody(BuildContext context)
  {
    return Column(
      children: [
        SingleChildScrollView(
          child: Container(
            child: content,
          ),
        ),
        InkWell(
            child: Container(
              child: Text('SAVE'),
            ),
            onTap: () => validationMessage() // => I changed this line
        ),
      ],
    );
  }
}

My new router:

case RouterName.kContentView1:
  return CupertinoPageRoute(
      builder: (context) => ChangeNotifierProvider<ContentView1Provider>(
        create: (BuildContext context) => ContentView1Provider(),
        child: TemplateView(
            title: "Content 1 page",
            message: Content1View(),
            validationMessage: () => Provider.of<ContentView1Provider>(context).saveMessage(),
        ),
      )
  );

It doesn't work, how to do this?

I am not sure if I understand this case well, but I just tell an Idea if it is work and if I understood what you ask: in your route pass provider to the Tamplate page:

case RouterName.kContentView1:
  return CupertinoPageRoute(
      builder: (context) => ChangeNotifierProvider<ContentView1Provider>(
        create: (BuildContext context) => ContentView1Provider(),
        child: TemplateView(
            provider : ContentView1Provider ,     // add this line
            title: "Content 1 page",
            message: Content1View(),
            validationMessage: () => Provider.of<ContentView1Provider>(context).saveMessage(),
        ),
      )
  );

in template view recieve this provider:

class TemplateView extends StatelessWidget{
  final provider;       //  add this line
  final String title;
  final StatelessWidget content;
  final Function validationMessage; // => I added this line
  TemplateView({
        Key? key,
        required this.provider,       //  add this line
        required this.title,
        required this.content,
        required this.validationMessage, // => I added this line
      }) : super(key: key);

now You can use Consumer with provider you recieved for each content:

return Consumer<provider>(builder :(ctx , provider , child){
   return //what you want ....;
})

May I have missunderstood

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM