English 中文(简体)
Flutter - using same provider for updating dropdown and sending to data to another widget
原标题:

I want to pass selected value from DropDown to its parent and then to child through constructor, after that update list by setState functions.

So, I want selected value from Dropdown be accessible in child of Restrictions (UserOffers).

Sending data from parent to child its actually working, but only when im passing data definied in parent class to child by constructor = im not sure if its a good way.

Now i am using provider to update data on Dropdown only, but i dont know how to pass it.

CountryProvider class:

class CountryProvider with ChangeNotifier {
  List<String> _items = [
    "Argentina",
    "Brazil",
    ...
   "Spain",
    "Switzerland",
  ];

  String _selectedItem;

  List<String> get items => _items;

  String get selected => _selectedItem;

  void setSelectedItem(String s) {
    _selectedItem = s;
    notifyListeners();
  }
}

CountryDropDown class:

class CountryDropDown extends StatefulWidget {
  @override
  _CountryDropDownState createState() => _CountryDropDownState();
}
class _CountryDropDownState extends State<CountryDropDown> {
  @override
  void initState() {
    super.initState();
  }
...
          ChangeNotifierProvider<CountryProvider>(
            create: (context) => CountryProvider(),
            child: Container(
              width: 215,
              child: Consumer<CountryProvider>(
                builder: (_, provider, __) {
                  return DropdownButton<String>(
                    hint: Text("Not selected"),
                    icon: Icon(Icons.flight),
                    value: dropdownValue,
                    onChanged: (String newValue) {
                      provider.setSelectedItem(newValue);
                      dropdownValue = provider.selected;
                      print(newValue);
                    },
                    items: provider.items
                        .map<DropdownMenuItem<String>>((String value) {
                      return DropdownMenuItem<String>(
                        value: value,
                        child: Text(value),
                      );
                    }).toList(),
                  );
...

And parent:

Restrictions class:

class Restrictions extends StatefulWidget {
  @override
  _RestrictionsState createState() => _RestrictionsState();
}

class _RestrictionsState extends State<Restrictions> {
  @override
  void initState() {
    super.initState();
  }
...
Column(
                  children: <Widget>[
                    Container(
                      margin: EdgeInsets.only(left: 20),
                      child: FieldDropDown(),
                    ),
                    Container(
                      padding: EdgeInsets.only(top: 10),
                      margin: EdgeInsets.only(left: 20),
                      child: CountryDropDown(),
                    ),
                  ],
                ),
                Container(
                  child: DateSelector(),
                ),
              ],
            ),
            Container(
              child: UserOffers(
                country: selectedCountry,
                field: selectedField,
              ),
...
最佳回答

@Boras ! You made a lot of work for me with all the ....

I think you need to lift state higher up the widget tree so that UserOffers can change when the user selects a country from the drop down menu.

Complete example app below.

Note that I changed the model class name to SingleSelectCountry. An instance of that model class is not a provider. An instance of that model class is what is being provided by a provider. There s an important distinction there.

Note also that all the widgets extend StatelessWidget. Often with package provider you can avoid using StatefulWidget.

import  dart:collection ;
import  package:flutter/material.dart ;
import  package:provider/provider.dart ;

// Model ---------------------------------------------------

class SingleSelectCountry with ChangeNotifier {
  final List<String> _items = <String>[
    "Argentina",
    "Belgium",
    "Brazil",
    "Denmark",
    "England",
    "France",
    "Finland",
    "Germany",
    "Holland",
    "Ireland",
    "Norway",
    "Poland",
    "Scotland",
    "Spain",
    "Sweden",
    "Switzerland",
    "Wales",
  ];

  String _selectedItem;

  UnmodifiableListView<String> get items {
    return UnmodifiableListView(this._items);
  }

  String get selected {
    return this._selectedItem;
  }

  set selected(final String item) {
    this._selectedItem = item;
    this.notifyListeners();
  }
}

// User Interface ------------------------------------------

void main() {
  return runApp(MyApp());
}

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

class MyHomePage extends StatelessWidget {
  @override
  Widget build(final BuildContext context) {
    // The provider has to be in the widget tree higher than
    // both `CountryDropDown` and `UserOffers`.
    return MultiProvider(
      providers: [
        ChangeNotifierProvider<SingleSelectCountry>(
          create: (final BuildContext context) {
            return SingleSelectCountry();
          },
        ),
      ],
      child: Scaffold(
        appBar: AppBar(
          title: Text( My Home Page ),
        ),
        body: Restrictions(),
      ),
    );
  }
}

class Restrictions extends StatelessWidget {
  @override
  Widget build(final BuildContext context) {
    return Column(
      children: <Widget>[
        CountryDropDown(),
        UserOffers(),
      ],
    );
  }
}

class CountryDropDown extends StatelessWidget {
  @override
  Widget build(final BuildContext context) {
    return Consumer<SingleSelectCountry>(
      builder: (
        final BuildContext context,
        final SingleSelectCountry singleSelectCountry,
        final Widget child,
      ) {
        return DropdownButton<String>(
          hint: const Text("Not selected"),
          icon: const Icon(Icons.flight),
          value: singleSelectCountry.selected,
          onChanged: (final String newValue) {
            singleSelectCountry.selected = newValue;
          },
          items: singleSelectCountry.items.map<DropdownMenuItem<String>>(
            (final String value) {
              return DropdownMenuItem<String>(
                value: value,
                child: Text(value),
              );
            },
          ).toList(),
        );
      },
    );
  }
}

class UserOffers extends StatelessWidget {
  @override
  Widget build(final BuildContext context) {
    return Consumer<SingleSelectCountry>(
      builder: (
        final BuildContext context,
        final SingleSelectCountry singleSelectCountry,
        final Widget child,
      ) {
        return Text(singleSelectCountry.selected ??   );
      },
    );
  }
}
问题回答

Thanks, it works, but now im struggling with implement it to DatePicker.

no need to use consumer for widget with ShowDatePicker just make callback with smth like Provider.of(context, listen: false).setDate1(DateTime.now())





相关问题
How can I make mobile version of an existing web site?

We have a website coded with jsp-Java. Now, we want to show our website more user friendly on blackberry etc. Is there any tool or method to do this issue more easier? thanks for your answers.

Should I make my mobile application for Mobile 6 or Mobile 5?

I am going to be making a small application very soon. I am wondering would it be better to go and make it for 6.0 or should I make it for 5.0? I don t know much about both versions but I guessing ...

How do I combine @font-face and @media declarations?

I d like to build a common typography stylesheet with a very small number of selectors. As such, I d far prefer to use @media sections for the various versions rather than create different files, each ...

热门标签