Как реализовать Слайдер в AlertDialog во Флаттере? - PullRequest
0 голосов
/ 02 января 2019

Я изучаю разработку приложений на Flutter и не могу заставить свой Slider работать в AlertDialog. Это не изменит его значение.
Я действительно искал проблему и наткнулся на этот пост на StackOverFlow:
Flutter - Почему слайдер не обновляется в AlertDialog?
Я прочитал это и как бы понял это. Принятый ответ говорит, что:

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

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

Вот как выглядит моя текущая реализация:

double _fontSize = 1.0;

@override
Widget build(BuildContext context) {
  return Scaffold(
      appBar: AppBar(
        title: Text(qt.title),
        actions: <Widget>[
          IconButton(
            icon: Icon(Icons.format_size),
            onPressed: () {
              getFontSize(context);
            },
          ),
        ],
      ),
      body: ListView.builder(
          padding: EdgeInsets.symmetric(vertical: 15.0),
          itemCount: 3,
          itemBuilder: (context, index) {
            if (index == 0) {
              return _getListTile(qt.scripture, qt.reading);
            } else if (index == 1) {
              return _getListTile('Reflection:', qt.reflection);
            } else {
              return _getListTile('Prayer:', qt.prayer);
            }
          })
  );
}

void getFontSize(BuildContext context) {
  showDialog(context: context,builder: (context){
    return AlertDialog(
      title: Text("Font Size"),
      content: Slider(
        value: _fontSize,
        min: 0,
        max: 100,
        divisions: 5,
        onChanged: (value){
          setState(() {
            _fontSize = value;
          });
        },
      ),
      actions: <Widget>[
        RaisedButton(
          child: Text("Done"),
          onPressed: (){},
        )
      ],
    );
  });
}


Widget parseLargeText(String text) {...}

Widget _getListTile(String title, String subtitle) {...}

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

1 Ответ

0 голосов
/ 03 января 2019

Вот минимальный работоспособный пример. Ключевые моменты:

  • Диалог - это виджет с сохранением состояния, в котором текущее значение сохраняется в State. Это важно, потому что диалоги - это технически отдельные «страницы» в вашем приложении, вставленные выше в иерархии
  • Navigator.pop(...), чтобы закрыть диалоговое окно и вернуть результат
  • Использование async / await

import 'package:flutter/material.dart';

void main() => runApp(App());

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  double _fontSize = 20.0;

  void _showFontSizePickerDialog() async {
    // <-- note the async keyword here

    // this will contain the result from Navigator.pop(context, result)
    final selectedFontSize = await showDialog<double>(
      context: context,
      builder: (context) => FontSizePickerDialog(initialFontSize: _fontSize),
    );

    // execution of this code continues when the dialog was closed (popped)

    // note that the result can also be null, so check it
    // (back button or pressed outside of the dialog)
    if (selectedFontSize != null) {
      setState(() {
        _fontSize = selectedFontSize;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            Text('Font Size: ${_fontSize}'),
            RaisedButton(
              onPressed: _showFontSizePickerDialog,
              child: Text('Select Font Size'),
            )
          ],
        ),
      ),
    );
  }
}

// move the dialog into it's own stateful widget.
// It's completely independent from your page
// this is good practice
class FontSizePickerDialog extends StatefulWidget {
  /// initial selection for the slider
  final double initialFontSize;

  const FontSizePickerDialog({Key key, this.initialFontSize}) : super(key: key);

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

class _FontSizePickerDialogState extends State<FontSizePickerDialog> {
  /// current selection of the slider
  double _fontSize;

  @override
  void initState() {
    super.initState();
    _fontSize = widget.initialFontSize;
  }

  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      title: Text('Font Size'),
      content: Container(
        child: Slider(
          value: _fontSize,
          min: 10,
          max: 100,
          divisions: 9,
          onChanged: (value) {
            setState(() {
              _fontSize = value;
            });
          },
        ),
      ),
      actions: <Widget>[
        FlatButton(
          onPressed: () {
            // Use the second argument of Navigator.pop(...) to pass
            // back a result to the page that opened the dialog
            Navigator.pop(context, _fontSize);
          },
          child: Text('DONE'),
        )
      ],
    );
  }
}
...