Flutter: возвращает данные из дочернего класса StatefulWidget в родительский

#flutter #dart #flutter-widget

#флаттер #dart #flutter-виджет

Вопрос:

Я новичок в flutter.

У меня есть страница (виджет с отслеживанием состояния) в приложении с множеством виджетов в столбце. Чтобы улучшить читаемость кода, я взял несколько виджетов и разделил их на отдельные классы. Например, я превратил свой виджет dropdownmenu в его единственный класс, например, так:

 class DropDownMenuWidget extends StatefulWidget {


  
  DropDownMenuWidget({Key? key}) : super(key: key);

  @override
  _DropDownMenuWidgetState createState() => _DropDownMenuWidgetState();
}

/// This is the private State class that goes with MyStatefulWidget.
class _DropDownMenuWidgetState extends State<DropDownMenuWidget> {



  String dropdownValue = 'One';

  @override
  Widget build(BuildContext context) {
    return DropdownButton<String>(
      value: dropdownValue,
      icon: Icon(Icons.arrow_downward),
      iconSize: 24,
      elevation: 16,
      style: TextStyle(
          color: Colors.black,
        fontSize: 20,

      ),
      underline: Container(
        height: 2,
        color: Colors.blue,
      ),
      onChanged: (String? newValue) {
        setState(() {
          dropdownValue = newValue!;
        });
      },
      items: MASLULIM
          .map<DropdownMenuItem<String>>((String value) {
        return DropdownMenuItem<String>(
          value: value,
          child: Text(value),
        );
      }).toList(),
    );
  }
}
 

Теперь в родительском классе я отображаю виджет следующим образом:

 DropDownMenuWidget(),
 

Однако проблема в том, что когда пользователь нажимает на элемент, я могу получить это значение только из класса DropDownMenu , и там вызывается метод setState() . Однако мне нужно прочитать это значение в родительском классе. Как я могу получить его там?

Спасибо

Ответ №1:

Вместо того, чтобы создавать свою dropdownValue переменную в своем виджете, вы можете получить ее из родительского виджета следующим образом с помощью ValueNotifier

 class DropDownMenuWidget extends StatefulWidget {
  ValueNotifier dropdownValueNotifier;
  DropDownMenuWidget(this.dropdownValueNotifier, {Key key}) : super(key: key);

  @override
  _DropDownMenuWidgetState createState() => _DropDownMenuWidgetState();
}

class _DropDownMenuWidgetState extends State<DropDownMenuWidget> {
  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder(
      valueListenable: widget.dropdownValueNotifier,
      builder: (context, dropdownValue, _) {
        return DropdownButton<String>(

          value: dropdownValue,

          // ...

          onChanged: (String newValue) {
            // simply change the value. You dont need setState anymore
            widget.dropdownValueNotifier.value = newValue;
          },

          // ...
        );
      },
    );
  }
}
 

В родительском виджете создайте переменную и передайте ее следующим образом

 ValueNotifier dropdownValueNotifier = ValueNotifier('One');

// ...

DropDownMenuWidget(dropdownValueNotifier),
 

Комментарии:

1. Вот как я получаю переменную для виджета, но как мне вернуть ее родительскому, когда пользователь выбирает ее? Спасибо

2. Сначала создайте переменную в родительском виджете, затем передайте ее дочерним по параметру. Как вы можете видеть выше

3. Я понимаю, что вы говорите, но тогда пользователь выберет другое значение в виджете, и это значение должно быть прочитано родителем

4. Лучшим подходом для этого является использование ValueNotifier

5. Проверьте новое решение

Ответ №2:

В этом случае вы можете использовать typedef

Сначала в отдельном выпадающем меню вы можете создать следующий значок вне класса:

 typedef OnItemSelectedDropDown = Function (String value);
 

Теперь вы можете применить это следующим образом :

 class DropDownMenuWidget extends StatefulWidget {

   final OnItemSelectedDropDown onItemSelected ;

  DropDownMenuWidget({Key? key}) : super(key: key);

  @override
  _DropDownMenuWidgetState createState() => _DropDownMenuWidgetState();
}

/// This is the private State class that goes with MyStatefulWidget.
class _DropDownMenuWidgetState extends State<DropDownMenuWidget> {



  String dropdownValue = 'One';

  @override
  Widget build(BuildContext context) {
    return DropdownButton<String>(
      value: dropdownValue,
      icon: Icon(Icons.arrow_downward),
      iconSize: 24,
      elevation: 16,
      style: TextStyle(
        color: Colors.black,
        fontSize: 20,

      ),
      underline: Container(
        height: 2,
        color: Colors.blue,
      ),
      onChanged: (String value) {
        //This line return Value
        widget.onItemSelected.call(value);
      },
      items: MASLULIM
          .map<DropdownMenuItem<String>>((String value) {
        return DropdownMenuItem<String>(
          value: value,
          child: Text(value),
        );
      }).toList(),
    );
  }
}
 

При вызове класса DropDownMenuWidget он вызывается следующим образом на другом экране:

 String dropdownValue ;
  @override
  Widget build(BuildContext context) {

    return Scaffold(
      appBar: AppBar(
        title: Text('DropDown Page'),
      ),
      body: Center(
        child: Column(

          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'New Value DropDown : $dropdownValue',
            ),
            DropDownMenuWidget(
                onItemSelected :(newValue){
                  setState(() {
                    dropdownValue = newValue ;
                  });
                }
            ),
          ],
        ),
      ),
    );
  }