Flutter - Почему слайдер не обновляется в AlertDialog?

Я делаю AlertDialog, поэтому, когда я пытался вставить виджет Slider в состояние значения, звучит очень странно, и этого не происходит, если Slider находится за пределами AlertDialog

new Slider(
  onChanged: (double value) {
    setState(() {
      sliderValue = value;
    });
  },
  label: 'Oi',
  divisions: 10,
  min: 0.0,
  max: 10.0,
  value: sliderValue,
)

Полный код виджета AlertDialog

Future<Null> _showDialog() async {
  await showDialog<Null>(
      context: context,
      builder: (BuildContext context) {
        return new AlertDialog(
          title: const Text('Criar novo cartão'),
          actions: <Widget>[
            new FlatButton(onPressed: () {
              Navigator.of(context).pop(null);
            }, child: new Text('Hello'))
          ],
          content: new Container(
            child: new Column(
              mainAxisAlignment: MainAxisAlignment.start,
              mainAxisSize: MainAxisSize.min,
              children: <Widget>[
                new Text('Deseja iniciar um novo cartão com quantos pedidos ja marcados?'),
                new Slider(
              onChanged: (double value) {
                setState(() {
                  sliderValue = value;
                });
              },
              label: 'Oi',
              divisions: 10,
              min: 0.0,
              max: 10.0,
              value: sliderValue,
            )
              ],
            ),
          ),
        );
      }
  );
}

и все находится в классе State StatefullWidget.

Похоже, что значение не обновляется, и при попытке изменить значение остается в том же положении.

Обновление 1

Проблема в том, что в Slider (onChanged, value) есть 2 обязательных параметра, поэтому я должен обновить его, или пользовательский интерфейс не изменится, посмотрите видео, как работает приложение.

Видео на Youtube

Обновление 2

Я также открыл проблему, чтобы получить помощь с этим в репозитории Github, если кто-то хочет получить дополнительную информацию, можно перейти на проблема № 19323


person Helio Soares Junior    schedule 10.07.2018    source источник


Ответы (5)


Проблема в том, что состояние хранится не в вашем диалоге. Это виджет, который называется showDialog. То же самое происходит, когда вы вызываете setState, вы вызываете создателя диалогового окна.

Проблема в том, что диалоги не построены внутри build метода. Они находятся в другом дереве виджетов. Поэтому, когда создатель диалогового окна обновляется, диалоговое окно не обновляется.

Вместо этого вы должны сделать свой диалог с отслеживанием состояния. Сохраните данные внутри этого диалогового окна. А затем используйте Navigator.pop(context, sliderValue), чтобы отправить значение ползунка обратно создателю диалогового окна.

Эквивалент в вашем диалоге будет

FlatButton(
  onPressed: () => Navigator.of(context).pop(sliderValue),
  child: Text("Hello"),
)

Что вы затем можете поймать в результате showDialog:

final sliderValue = await showDialog<double>(
  context: context,
  builder: (context) => MyDialog(),
)
person Rémi Rousselet    schedule 10.07.2018
comment
Извините за задержку, поэтому сначала спасибо, но как насчет требуемых методов на Slider (onChange, value), оба требуются, если я устанавливаю какое-либо значение, которое я не могу обновить состояние, на пользователе, попробуйте переместить слайдер, который он держит на в том же месте, я думаю, что если я изменю, это останется прежним, ползунок обновляет состояние, когда он закрывается, но проблема в том, что когда пользователь перетаскивает для перемещения, изменений нет - person Helio Soares Junior; 13.07.2018
comment
Я также отредактировал вопрос, чтобы добавить видео, показывающее это - person Helio Soares Junior; 13.07.2018
comment
Это сработало! Извините, я сейчас начинаю с флаттера, поэтому я кое-что запутала ... еще раз спасибо - person Helio Soares Junior; 13.07.2018
comment
@ remi-rousselet Я думаю, мне не хватает того, как сделать свой диалог с отслеживанием состояния. Можно ли это сделать с помощью собственного класса ShowDialog? - person Cystack; 24.01.2019
comment
@Cystack У меня возник тот же вопрос, когда я читал его ответ. Я взял все из конструктора и вырезал из него виджет с отслеживанием состояния. В какой-то момент у вас, вероятно, будет что-то вроде этого ... return showDialog (context: context, барьерDismissible: false, builder: (context) {return SimpleDialog (...... Заполните SimpleDialog Cut, начиная со слова return, и поставьте это в конструкторе вашего виджета с отслеживанием состояния. - person Eric Duffett; 21.03.2019

Я столкнулся с той же проблемой с флажком, и это мое решение, даже если это не лучший подход. (см. комментарий в коде)

Future<Null>_showDialog() async {
  return showDialog < Null > (
    context: context,
    barrierDismissible: true,
    builder: (BuildContext context) {
      return new AlertDialog(
        title: Text("title"),
        content: Container(
          height: 150.0,
          child: Checkbox(
            value: globalSearch,
            onChanged: (bool b) {
              print(b);
              globalSearch = b;
              Navigator.of(context).pop(); // here I pop to avoid multiple Dialogs
              _showDialog(); //here i call the same function
            },
          )),
      );
    },
  );
}
person Raoul Scalise    schedule 28.08.2018
comment
Спасибо, что поделились!! Это мне действительно помогло. Я пытаюсь создать сложный диалог, в котором у меня есть раскрывающиеся меню, и возвращение состояния родительскому виджету из нескольких раскрывающихся списков напрягало мой мозг. Но это решение, похоже, работает достаточно хорошо. Просто откройте диалоговое окно и снова вызовите его. - person Eradicatore; 29.07.2019
comment
Его нельзя использовать в случае слайдера, потому что, когда мы скользим, диалоговое окно выскакивает, и мы не получаем непрерывности при прокрутке. - person Bensal; 01.01.2021

Самый простой и минимальный объем строк: используйте StatefulBuilder в качестве верхнего виджета содержимого в AlertDialog.

                StatefulBuilder(
                  builder: (context, state) => CupertinoSlider(
                    value: brightness,
                    onChanged: (val) {
                      state(() {
                        brightness = val;
                      });
                    },
                  ),
                ));
person cmd_prompter    schedule 11.09.2020

У меня была аналогичная проблема, и я решил ее, поместив все из AlertDialog в StatefullWidget.

    class <your dialog widget> extends StatefulWidget {
  @override
  _FilterDialogState createState() => _FilterDialogState();
}

class _<your dialog widget> extends State<FilterDialog> {

  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      //your alert dialog content here
    );
  }
}
person kenjmoj    schedule 25.05.2020

создайте класс с полным состоянием с ползунком во время возврата, а двойное значение должно быть объявлено внутри класса с полным состоянием, поэтому функция setstate будет работать.

вот пример, который я сделал для своего всплывающего слайдера, то же самое, что и для диалогового окна предупреждения, можно объявить переменную как глобальную, поэтому к ней могут получить доступ другие классы

    class _PopupMenuState extends State<PopupMenu> {
      double _fontSize=15.0;
    
      @override
      Widget build(BuildContext context) {
        return Container(
          child: Slider(
            value: _fontSize,
            min: 10,
            max: 100,
            onChanged: (value) {
              setState(() {
                print(value);
                _fontSize = value;
              });
            },
          ),
        );
      }
    }
person Anoop Benzier    schedule 29.09.2020