我有一个代码,负责按特定类别进行过滤(为了便于阅读,我缩短了它).当打开过滤器窗口时,用户会看到这些类别名称(" Select 品牌"、" Select 操作系统"、" Select colored颜色 "等).

接下来,用户可以打开类别(最初,下拉列表处于关闭位置),然后从下拉列表中 Select 参数(并单击应用按钮).下次打开"过滤器"窗口时,参数前面的复选框将保留,但下拉列表将折叠.

告诉我怎么做:如果在任何类别中有带有复选标记的选项,那么下拉列表将在下次打开带有过滤器的窗口时打开.

     class FilterDialog extends StatefulWidget {
  final void Function(Map<String, List<String>?>) onApplyFilters;

  final Map<String, List<String>?> initialState;

  const FilterDialog({
    Key? key,
    required this.onApplyFilters,
    this.initialState = const {},
  }) : super(key: key);

  @override
  State<FilterDialog> createState() => _FilterDialogState();
}

class _FilterDialogState extends State<FilterDialog> {
  // Temporary storage of filters.
  Map<String, List<String>?> filters = {};
  bool needRefresh = false;

  // Variable for the ability to hide all elements of filtering by any parameter.
  bool isClickedBrand = false;


  List manufacturer = [];


  @override
  void initState() {
    super.initState();
    filters = widget.initialState;
  }

  // A function to be able to select an element to filter.
  void _handleCheckFilter(bool checked, String key, String value) {
    final currentFilters = filters[key] ?? [];
    if (checked) {
      currentFilters.add(value);
    } else {
      currentFilters.remove(value);
    }
    setState(() {
      filters[key] = currentFilters;
    });
  }

  // Building a dialog box with filters.
  @override
  Widget build(BuildContext context) {
    return SimpleDialog(
      // Window title.

      title: const Text('Filters',
          textAlign: TextAlign.center,
          style: TextStyle(
            fontSize: 25,
            fontWeight: FontWeight.w600,
          )),
      contentPadding: const EdgeInsets.all(16),

      // Defining parameters for filtering.
      children: [
        Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            // Here and in subsequent Column, there will be a definition of parameters for filtering,
            // a title, the ability to hide/show the items of list
            Column(children: [
              InkWell(
                  onTap: () async {
                    manufacturer = await getManufacturerOptions();
                    setState(() {
                      isClickedBrand = !isClickedBrand;
                    });
                  },
                  child: Row(children: [
                    Text('Select a brand'.toString(),
                        style: const TextStyle(
                          fontSize: 18,
                        )),
                    const Spacer(),
                    isClickedBrand
                        ? const Icon(Icons.arrow_circle_up)
                        : const Icon(Icons.arrow_circle_down)
                  ])),
              !isClickedBrand
                  ? Container()
                  : Column(
                      children: manufacturer
                          .map(
                            (el) => CustomCheckboxTile(
                              value: filters['manufacturer']?.contains(el) ??
                                  false,
                              label: el,
                              onChange: (check) =>
                                  _handleCheckFilter(check, 'manufacturer', el),
                            ),
                          )
                          .toList())
            ]),
            const SizedBox(
              height: 5,
            ),



            // Building a button to apply parameters.
            const SizedBox(
              height: 10,
            ),
            ElevatedButton(
                onPressed: () {
                  Navigator.of(context).pop();
                  widget.onApplyFilters(filters);
                  needRefresh = true;
                },
                child:
                    const Text('APPLY', style: TextStyle(color: Colors.black)),
                style: ButtonStyle(
                  backgroundColor: MaterialStateProperty.all(Colors.grey),
                )),

            // Building a button to reset parameters.
            const SizedBox(
              height: 5,
            ),
            ElevatedButton(
                onPressed: () async {
                  setState(() {
                    filters.clear();
                  });
                  widget.onApplyFilters(filters);
                },
                child: const Text('RESET FILTERS',
                    style: TextStyle(color: Colors.black)),
                style: ButtonStyle(
                  backgroundColor: MaterialStateProperty.all(Colors.grey),
                )),
          ],
        ),
      ],
    );
  }
}

例如:用户单击过滤器框, Select 要搜索的品牌,然后单击应用按钮.我的任务是,下次用户打开过滤器窗口时,带有活动复选框的类别(在本例中为品牌)处于展开状态

enter image description here

推荐答案

其概念是,在打开对话框时需要判断过滤器数据,以简化我使用ExpansionTile的过程.您可以查看此演示并自定义行为和外观.

dartPad上运行,单击fab打开对话框,touch 对话框外部以关闭此对话框.

class ExTExpample extends StatefulWidget {
  ExTExpample({Key? key}) : super(key: key);

  @override
  State<ExTExpample> createState() => _ExTExpampleState();
}

class _ExTExpampleState extends State<ExTExpample> {
  // you can use map or model class or both,
  List<String> filter_data = [];
  List<String> brands = ["Apple", "SamSung"];
  List<String> os = ["iOS", "Android"];

  _showFilter() async {
    await showDialog(
      context: context,
      builder: (c) {
        // you can replace [AlertDialog]
        return AlertDialog(
          content: StatefulBuilder(
            builder: (context, setSBState) => SingleChildScrollView(
              child: Column(
                mainAxisSize: MainAxisSize.min,
                children: [
                  ExpansionTile(
                    title: const Text("Brand"),

                    /// check any of its's item is checked or not
                    initiallyExpanded: () {
                      // you can do different aproach
                      for (final f in brands) {
                        if (filter_data.contains(f)) return true;
                      }
                      return false;
                    }(),
                    children: [
                      ...brands.map(
                        (brandName) => CheckboxListTile(
                          value: filter_data.contains(brandName),
                          title: Text(brandName),
                          onChanged: (v) {
                            if (filter_data.contains(brandName)) {
                              filter_data.remove(brandName);
                            } else {
                              filter_data.add(brandName);
                            }

                            setSBState(() {});
                            //you need to reflect the main ui, also call `setState((){})`
                          },
                        ),
                      ),
                    ],
                  ),
                  ExpansionTile(
                    title: const Text("select OS"),

                    /// check any of its's item is checked or not
                    initiallyExpanded: () {
                      // you can do different aproach
                      for (final f in os) {
                        if (filter_data.contains(f)) return true;
                      }
                      return false;
                    }(),
                    children: [
                      ...os.map(
                        (osName) => CheckboxListTile(
                          value: filter_data.contains(osName),
                          title: Text(osName),
                          onChanged: (v) {
                            if (filter_data.contains(osName)) {
                              filter_data.remove(osName);
                            } else {
                              filter_data.add(osName);
                            }

                            setSBState(() {});
                            //you need to reflect the main ui, also call `setState((){})`
                          },
                        ),
                      ),
                    ],
                  ),
                ],
              ),
            ),
          ),
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: FloatingActionButton(
          onPressed: () {
            _showFilter();
          },
        ),
      ),
    );
  }
}

Flutter相关问答推荐

当仅点击一行时,所有行都被选中

错误:找不到字体功能类型.Ffltter Google_Fonts包错误

Build.gradle专线:2个Flutter Flutter

为什么Flutter InAppWebView中的DatePicker看起来很旧?

如何在扩展其他小部件时访问Ref

Flutter 蜂巢不能正常工作,我正在使用蜂巢在设备上存储数据,但当我关闭并重新启动应用程序时,我失go 了一切

如何将请求字段正确添加到DART多部分请求

在创建显示此错误的Flutter 深度链接时

使用Ffltter CREATE创建项目时,androidManifest.xml中缺少包属性

如何在flutter中使用youtube_explod_start加载下一页

我如何在Android 13中通过Flutter应用程序打开文件(不是图像、视频或音频)?

在允许屏幕 Select 和点击的同时保持通用对话框显示

Flutter ListView 在调用 setState 后未更新

我想在文本结束后显示分隔线.它会在第一行、第二行或第三行结束

如何防止键盘将内容向上推?

Firebase 中的查询限制 - .orderBy() 错误

无法将参数类型Future Function(String?)分配给参数类型void Function(NotificationResponse)?

配置项目:firebase_core时出现问题

如何在Flutter 中制作自定义微调器?

如何从 Dart 中的两个不同列表创建公共元素列表?