Flutter - 为什么在AlertDialog中滑块不会更新?

13

我正在创建一个AlertDialog,但当我尝试在其状态中插入Slider小部件时,声音听起来非常奇怪。如果Slider小部件不在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,
            )
              ],
            ),
          ),
        );
      }
  );
}

一切都在StatefullWidget的State类下。

看起来它没有更新值,当尝试改变值时保持在相同的位置。

更新1

问题在于Slider中有2个必需参数(onChanged, value),所以我应该更新这个或者UI保持安静,观看视频以了解应用程序如何运行。

Youtube上的视频

更新2

我还在Github仓库中开了一个问题以获得帮助,如果有人想获取更多信息,可以前往问题#19323

5个回答

14

问题在于它不是你的对话框持有状态,而是调用了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(),
)

抱歉耽擱了,首先感謝,但是關於 Slider 上所需的方法(onChange、value),兩者都是必需的。如果我設置了任何值,當用戶嘗試移動 Slider 時,我無法更新狀態,它會一直保持在同一位置。我認為如果我改變這個,它仍然會保持不變,Slider 只有在接近時才會更新狀態,但問題是當用戶拖動移動時,沒有任何變化。 - Helio Soares Junior
我还编辑了问题,添加了一个视频展示这个。 - Helio Soares Junior
成功了!抱歉,我现在才开始使用Flutter,所以有些事情让我感到困惑...再次感谢。 - Helio Soares Junior
1
@remi-rousselet 我觉得我不明白你是如何“使你的对话框具有状态”。是否可以使用本地的ShowDialog类来完成? - Cystack
@ Cystack 当我阅读他的答案时,我也有同样的问题。我的做法是将构建器内部的所有内容剪切到有状态部件中。在某些时候你可能会遇到这种情况...返回 showDialog(context: context, barrierDismissible: false, builder: (context) { return SimpleDialog( ...... 填写SimpleDialog从单词"return"开始剪切并将其放入你的有状态部件的构建器中。 - Eric Duffett

5

我也遇到了与复选框相关的问题,并想出了解决方案,即使它不是最佳方法。(请查看代码中的注释)

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
            },
          )),
      );
    },
  );
}

1
谢谢分享!这真的帮了我很多。我正在尝试做一个复杂的对话框,其中有下拉菜单,并将多个下拉菜单的状态返回到父部件,这让我感到很困惑。但是这个解决方案似乎非常有效。只需弹出并再次调用对话框即可。 - Eradicatore
1
它不能用于滑块的情况,因为当我们滑动时,对话框会弹出,我们无法在滚动中获得连续性。 - Bensal

5
最简单且最少代码行数的方法: 在AlertDialog中,使用StatefulBuilder作为Content的顶部widget。
                StatefulBuilder(
                  builder: (context, state) => CupertinoSlider(
                    value: brightness,
                    onChanged: (val) {
                      state(() {
                        brightness = val;
                      });
                    },
                  ),
                ));

3

我曾经遇到过类似的问题,通过将所有内容放入StatefullWidget中的AlertDialog中解决了问题。

    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
    );
  }
}

0
创建一个有状态的类,滑块应该在返回时间内,并且双重值应该在有状态的类中声明,因此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;
              });
            },
          ),
        );
      }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接