11
votes

I doing a AlertDialog, so when I tried to insert Slider widget inside the state of value sound realy stranger, and this doesn't happens if Slider is outside of AlertDialog

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

The complete widget code of 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,
            )
              ],
            ),
          ),
        );
      }
  );
}

and everything is under State class of StatefullWidget.

Its look like doesn't update the value and when try to change the value keep in same position.

Update 1

The problem is there are 2 required parameters in Slider (onChanged, value), So I shoud update this or UI keep quite, see the video how the aplication is running

Video on Youtube

Update 2

I've also opened a issue to get help with this at Github repository, if someone wants to get more information can go to issue #19323

5

5 Answers

12
votes

The problem is that it's not your dialog that holds the state. It's the widget that called showDialog. Same goes for when you call setState, you are calling in on the dialog creator.

The problem is, dialogs are not built inside build method. They are on a different widget tree. So when the dialog creator updates, the dialog won't.

Instead, you should make your dialog stateful. Hold the data inside that dialog. And then use Navigator.pop(context, sliderValue) to send the slider value back to the dialog creator.

The equivalent in your dialog would be

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

Which you can then catch inside the showDialog result :

final sliderValue = await showDialog<double>(
  context: context,
  builder: (context) => MyDialog(),
)
5
votes

I've come up with the same issue with a checkbox and that's my solution, even if it's not the best approach. (see the comment in the code)

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

Easiest and least amount of lines: Use StatefulBuilder as top widget of Content in the AlertDialog.

                StatefulBuilder(
                  builder: (context, state) => CupertinoSlider(
                    value: brightness,
                    onChanged: (val) {
                      state(() {
                        brightness = val;
                      });
                    },
                  ),
                ));
1
votes

I had similar issue and resolved by putting everything under AlertDialog in to a 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
    );
  }
}
0
votes

create a statefull class with the slider at the return time and the double value should declare inside the statefull class thus the setstate func will work.

here is an example i done this for my slider popup its same for alert dialog use can declare the variable as global thus it can be accessed by other classes

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