Как сделать недействительным дочерний виджет флаттера - PullRequest
0 голосов
/ 29 октября 2019

Я начинаю изучать Flutter, и мне любопытно, как передать данные между виджетами и сделать представление недействительным (перерисовать), когда я изменяю данные (состояние) в родительском виджете.

Я пытался сделать пользовательскийВиджет под названием Spinner: https://developer.android.com/guide/topics/ui/controls/spinner

Итак, я создал следующие классы:

class SpinnerWidget<T> extends StatefulWidget {
  final SpinnerAdapter<T> adapter;
  final String hint;
  final bool allowClear;
  final Function(T) onChanged;

  SpinnerWidget({this.adapter, this.hint, this.allowClear, this.onChanged, Key key}) : super(key: key);

  @override
  _SpinnerWidgetState createState() =>
      _SpinnerWidgetState(this.adapter, this.hint, this.allowClear, this.onChanged);
}
class _SpinnerWidgetState<T> extends State<SpinnerWidget> {
  SpinnerAdapter<T> adapter;
  String hint;
  bool allowClear;
  Function(T) onChanged;

  T _selectedValue;

  _SpinnerWidgetState(this.adapter, this.hint, this.allowClear, this.onChanged);

  @override
  Widget build(BuildContext context) {
    return Container(
      decoration: ShapeDecoration(
        shape: RoundedRectangleBorder(
            side: BorderSide(
                width: 1.0,
                style: BorderStyle.solid,
                color: Theme.of(context).textTheme.display1.color),
            borderRadius: BorderRadius.all(Radius.circular(5.0))),
      ),
      child: Padding(
          padding: EdgeInsets.symmetric(horizontal: 12),
          child: DropdownButton<T>(
            value: _selectedValue,
            hint: Text(hint),
            isExpanded: true,
            underline: Container(
              height: 0,
            ),
            icon: allowClear ? (_selectedValue == null
                ? Icon(Icons.arrow_drop_down)
                : IconButton(
                    icon: Icon(Icons.close),
                    padding: EdgeInsets.all(0.0),
                    onPressed: () {
                      setState(() {
                        _selectedValue = null;
                      });
                      if(onChanged != null)
                        onChanged(null);
                    },
                  )):Icon(Icons.arrow_drop_down),
            items: adapter.getDropdownItems(),
            onChanged: (T newValue) {
              setState(() {
                _selectedValue = newValue;
              });
              if(onChanged != null)
                onChanged(newValue);
            },
          )),
    );
  }
}
abstract class SpinnerAdapter<T> {
  final List<T> _items;

  SpinnerAdapter(this._items);

  Widget getChildWidget(T item);

  List<DropdownMenuItem<T>> getDropdownItems() {
    return _items.map((T item) => DropdownMenuItem(
      value: item,
      child: getChildWidget(item),
    ))
    .toList();
  }
}

Теперь в родительском виджете называется RegistrationPage

class RegistrationPage extends StatefulWidget {
  RegistrationPage({Key key}) : super(key: key);

  @override
  _RegistrationPageState createState() => _RegistrationPageState();
}
class _RegistrationPageState extends State<RegistrationPage> {
  MjesnaZajednicaAdapter adapter = MjesnaZajednicaAdapter(["One", "Two", "Three", "Four"]);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // ...
          SpinnerWidget<String>(
            adapter: adapter,
            hint: "Mjesna Zajednica",
            allowClear: true,
          ), // SpinnerWidget
      // ...
    ); // Scaffold
  }

  onUpdateSpinnerDataButtonPressed() {
    setState(() {
      adapter = MjesnaZajednicaAdapter(["Jedan", "Dva", "Tri", "Cetiri", "Pet"]);
    });
  }
}

Но когда я нажимаю эту кнопку, которая появляется у меня на экране, и выполняется метод onUpdateSpinnerDataButtonPressed, у меня остаются те же значения в Spinner.

Любая помощь в том, как мне обновить состояние потомков. Я прочитал кое-что о GlobalKey и попробовал это, но я не уверен, как использовать это, когда иерархия виджетов состоит из нескольких уровней.

Например, что если у меня что-то вроде этого:

RegistrationPage -> RegistrationForm -> SpinnerWidget

Теперь в RegistrationPage я вызвал службу для извлечения данных из Интернета для виджета счетчика, тогда мне нужночтобы передать это в регистрационную форму, которая, наконец, передаст ее SpinnerWidget ... Я знаю, что могу вызвать службу из виджета RegistrationForm, но только для примера, я хочу вызвать ее из RegistrationPage.

...