Flutter - 使用相同的提供者更新下拉列表并将数据发送到另一个小部件

Flutter - using same provider for updating dropdown and sending to data to another widget

我想将所选值从 DropDown 传递到它的 parent,然后通过构造函数传递到 child,然后通过 setState 函数更新列表。

因此,我希望可以在限制 (UserOffers) 的 child 中访问从下拉列表中选择的值。

将数据从 parent 发送到 child 它确实有效,但仅当我将 parent class 中定义的数据传递给 child 时由构造函数 =我不确定这是否是一个好方法。

现在我正在使用提供程序来更新下拉列表中的数据,但我不知道如何传递它。

国家提供者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(),
                  );
...

和parent:

限制条件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! ....

你为我做了很多工作

我认为您需要将状态提升到小部件树的更高位置,以便 UserOffers 可以在用户从下拉菜单中选择国家/地区时更改。

完成下面的示例应用程序。

请注意,我将模型 class 名称更改为 SingleSelectCountry。该模型 class 的实例不是提供者。该模型的一个实例 class 是提供者提供的。这里有一个重要的区别。

另请注意,所有小部件都扩展了 StatelessWidget。通常与包提供者你可以避免使用 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 ?? '');
      },
    );
  }
}