警报对话框中复选框磁贴的动态列表不起作用

时间:2018-09-10 06:27:56

标签: flutter alertdialog

关于如何在对话框中实现复选框并设置状态为工作状态尚无明确答案。

打印语句在设置复选框的状态时没有变化,但其他语句在起作用。在哪里可以找到答案?

我正在使用一个带有多个复选框的对话框以进行多选。还有在Flutter中实现多选的另一种方法吗?

   child: TextFormField(
     decoration: InputDecoration(
         labelText: 'Team Leader',
         labelStyle: TextStyle(color: Colors.black)),
     controller: teamLeaderController,
     enabled: false,
     style: TextStyle(color: Colors.black),
   ),
   onTap: () {
     showDialog(
         context: context,
         barrierDismissible: true,
         builder: (BuildContext context) {
           return CheckBoxDialog(context, teamLeader,
               "Choose Team Leader", teamLeaderController, onSubmit);
         });
   }),

class CheckBoxState extends State<CheckBoxDialog> {
  BuildContext context;
  List<String> places;
  String title;
  TextEditingController con;
  bool state;
  CheckBoxState(this.context, this.places, this.title, this.con);

  @override
  void initState() {
    super.initState();
    state = false;
  }

  @override
  Widget build(BuildContext context) {
    return new AlertDialog(
      title: new Text(title),
      content:
          Column(children: getMultiSelectOption(context, places, con, state)),
      actions: <Widget>[
        FlatButton(
            child: Text('Cancel'),
            onPressed: () {
              Navigator.of(context).pop();
            }),
        FlatButton(
            child: Text('Ok'),
            onPressed: () {
              widget.onSubmit("");
              Navigator.of(context).pop();
            })
      ],
    );
  }

  List<Widget> getMultiSelectOption(BuildContext context, List<String> places,
      TextEditingController con, bool state) {
    List<Widget> options = [];
    List<String> selectedList = [];
    for (int i = 0; i < places.length; i++) {
      options.add(CheckboxListTile(
          title: Text(places[i]),
          value: selectedList.contains(places[i]),
          onChanged: (bool value) {
            print("on change: $value  title: ${places[i]}");
            setState(() {
              if (value) {
                selectedList.add(places[i]);
              } else {
                selectedList.remove(places[i]);
              }
              print("contains: ${selectedList.contains(places[i])}");
              print("status: $value");
            });
          }));
    }
    return options;
  }
}

1 个答案:

答案 0 :(得分:0)

假设您有一个带有某些小部件的对话框,例如RadioListTile,DropdowButton…或可能需要更新的任何东西,而对话框仍然可见,该怎么做?

在这里查看此示例。 https://www.didierboelens.com/2018/05/hint-5-how-to-refresh-the-content-of-a-dialog-via-setstate/

假设您有一个带有某些小部件的对话框,例如RadioListTile,DropdowButton…或可能需要更新的任何东西,而对话框仍然可见,该怎么做?

难度:初学者

背景 最近,我不得不显示一个对话框以允许用户从列表中选择一个项目,并且我想显示RadioListTile的列表。

通过以下源代码,我可以毫无问题地显示对话框并显示列表:

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';

class Sample extends StatefulWidget {
  @override
  _SampleState createState() => new _SampleState();
}

class _SampleState extends State<Sample> {
  List<String> countries = <String>['Belgium','France','Italy','Germany','Spain','Portugal'];
  int _selectedCountryIndex = 0;

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_){_showDialog();});
  }

  _buildList(){
    if (countries.length == 0){
      return new Container();
    }

    return new Column(
      children: new List<RadioListTile<int>>.generate(
        countries.length,
        (int index){
          return new RadioListTile<int>(
            value: index,
            groupValue: _selectedCountryIndex,
            title: new Text(countries[index]),
            onChanged: (int value) {
              setState((){
                _selectedCountryIndex = value;
              });
            },
          );
        }
      )
    );
  }

  _showDialog() async{
    await showDialog<String>(
      context: context,
      builder: (BuildContext context){
        return new CupertinoAlertDialog(
          title: new Text('Please select'),
          actions: <Widget>[
            new CupertinoDialogAction(
              isDestructiveAction: true,
              onPressed: (){Navigator.of(context).pop('Cancel');},
              child: new Text('Cancel'),
            ),
            new CupertinoDialogAction(
              isDestructiveAction: true,
              onPressed: (){Navigator.of(context).pop('Accept');},
              child: new Text('Accept'),
            ),
          ],
          content: new SingleChildScrollView(
            child: new Material(
              child: _buildList(),
            ),
          ),
        );
      },
      barrierDismissible: false,
    );
  }

  @override
  Widget build(BuildContext context) {
    return new Container();
  }
}

令我惊讶的是,尽管在第34-36行中设置了setState,但是当用户点击其中一个项目时,所选RadioListTile并没有刷新。

说明 经过一番调查,我意识到setState()是指在其中调用setState的有状态小部件。在此示例中,对setState()的任何调用都会重建Sample Widget的视图,而不是对话框的内容之一。因此,该怎么办?

解决方案 一个非常简单的解决方案是创建另一个呈现对话框内容的有状态窗口小部件。然后,对setState的任何调用都将重建对话框的内容。

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';

class Sample extends StatefulWidget {
  @override
  _SampleState createState() => new _SampleState();
}

class _SampleState extends State<Sample> {
  List<String> countries = <String>['Belgium','France','Italy','Germany','Spain','Portugal'];

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_){_showDialog();});
  }

  _showDialog() async{
    await showDialog<String>(
      context: context,
      builder: (BuildContext context){
        return new CupertinoAlertDialog(
          title: new Text('Please select'),
          actions: <Widget>[
            new CupertinoDialogAction(
              isDestructiveAction: true,
              onPressed: (){Navigator.of(context).pop('Cancel');},
              child: new Text('Cancel'),
            ),
            new CupertinoDialogAction(
              isDestructiveAction: true,
              onPressed: (){Navigator.of(context).pop('Accept');},
              child: new Text('Accept'),
            ),
          ],
          content: new SingleChildScrollView(
            child: new Material(
              child: new MyDialogContent(countries: countries),
            ),
          ),
        );
      },
      barrierDismissible: false,
    );
  }

  @override
  Widget build(BuildContext context) {
    return new Container();
  }
}

class MyDialogContent extends StatefulWidget {
  MyDialogContent({
    Key key,
    this.countries,
  }): super(key: key);

  final List<String> countries;

  @override
  _MyDialogContentState createState() => new _MyDialogContentState();
}

class _MyDialogContentState extends State<MyDialogContent> {
  int _selectedIndex = 0;

  @override
  void initState(){
    super.initState();
  }

  _getContent(){
    if (widget.countries.length == 0){
      return new Container();
    }

    return new Column(
      children: new List<RadioListTile<int>>.generate(
        widget.countries.length,
        (int index){
          return new RadioListTile<int>(
            value: index,
            groupValue: _selectedIndex,
            title: new Text(widget.countries[index]),
            onChanged: (int value) {
              setState((){
                _selectedIndex = value;
              });
            },
          );
        }
      )
    );
  }

  @override
  Widget build(BuildContext context) {
    return _getContent();
  }
}