简体   繁体   English

在下拉按钮中单击时复选框不会更改

[英]Checkbox doesn't change when clicked in dropdownbutton

I am using DropdownButton and I am facing the following issue.我正在使用DropdownButton并且面临以下问题。 I'm using a checkbox in elements, but when I click on an element, I don't get a checkmark indicating that the checkbox has been clicked.我在元素中使用了一个复选框,但是当我点击一个元素时,我没有看到一个复选标记,表明该checkbox已被点击。 As a result, I need to close and reopen it, and then I will see the changes that were clicked on the " checkbox ".结果,我需要关闭并重新打开它,然后我会看到在“ checkbox ”上单击的更改。 The second problem is that when I select one element, all elements are selected for me.第二个问题是当我select一个元素时,所有元素都给我选了。 As a final result, I need to get so that I can select an element and the checkbox is immediately marked, if 2 elements are needed, then two, and so on.作为最终结果,我需要获取 select 一个元素并立即标记checkbox ,如果需要 2 个元素,则为两个,依此类推。 Tell me how to fix these problems, I will be grateful for the help?告诉我如何解决这些问题,我将不胜感激?

dropdown落下

class DropdownWidget extends StatefulWidget {
  List<String> items;
  SvgPicture? icon;
  double width;

  DropdownWidget({
    Key? key,
    required this.items,
    required this.icon,
    required this.width,
  }) : super(key: key);

  @override
  State<DropdownWidget> createState() => _DropdownWidgetState();
}

class _DropdownWidgetState extends State<DropdownWidget> {
  String? selectedValue;
  bool isChecked = false;

  @override
  void initState() {
    super.initState();
    if (widget.items.isNotEmpty) {
      selectedValue = widget.items[1];
    }
  }

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: widget.width,
      child: DropdownButtonHideUnderline(
        child: DropdownButton2(
          items: widget.items
              .map((item) => DropdownMenuItem<String>(
                    value: item,
                    child: Container(
                      decoration: BoxDecoration(
                        border: Border(
                          bottom: BorderSide(
                            color: constants.Colors.white.withOpacity(0.1),
                            width: 1,
                          ),
                        ),
                      ),
                      child: Center(
                        child: Row(
                          children: [
                            if (item == selectedValue)
                              const SizedBox(
                                width: 0,
                              ),
                            Expanded(
                              child: Text(
                                item,
                                style: constants.Styles.smallTextStyleWhite,
                              ),
                            ),
                            Checkbox(
                              checkColor: Colors.black,
                              value: isChecked,
                              onChanged: (bool? value) {
                                setState(() {
                                  isChecked = value!;
                                });
                              },
                            ),
                          ],
                        ),
                      ),
                    ),
                  ))
              .toList(),
          value: selectedValue,
          onChanged: (value) {
            setState(() {
              selectedValue = value as String;
            });
          },
          icon: SvgPicture.asset(constants.Assets.arrowDropdown),
          iconSize: 21,
          buttonHeight: 27,
          itemHeight: 47,
          dropdownMaxHeight: 191,
          dropdownWidth: 140,
          dropdownDecoration: BoxDecoration(
            borderRadius: BorderRadius.circular(8),
            border: Border.all(
              color: constants.Colors.purpleMain,
            ),
            color: constants.Colors.greyDark,
          ),
          selectedItemBuilder: (context) {
            return widget.items.map(
              (item) {
                return Row(
                  children: [
                    widget.icon ?? const SizedBox(),
                    const SizedBox(width: 8),
                    Text(
                      item,
                      style: constants.Styles.bigBookTextStyleWhite,
                    ),
                  ],
                );
              },
            ).toList();
          },
        ),
      ),
    );
  }
}

items项目

final List<String> items = const [
    "All EV's",
    'Main EV',
    '<EV2>',
  ];

I hope this example explains the concept.我希望这个例子能解释这个概念。 For simplcity I made simple a new file, run it and see the results:为了简单起见,我制作了一个简单的新文件,运行它并查看结果:

Then main idea in two lists, _checkList contain values of the CheckBox and _selectedList handles the main dropdown widget to show the selection.然后在两个列表中的主要思想, _checkList包含CheckBox的值和_selectedList处理主下拉小部件以显示选择。

Feel free to ask any questions and I'm happy to help随时提出任何问题,我很乐意提供帮助

import 'package:flutter/material.dart';

class TestPage extends StatelessWidget {
  const TestPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const AnimationDemo(number: 5);
  }
}

class AnimationDemo extends StatefulWidget {
  const AnimationDemo({Key? key, this.number = 2}) : super(key: key);
  final int number;

  @override
  State<AnimationDemo> createState() => _AnimationDemoState();
}

class _AnimationDemoState extends State<AnimationDemo> {
  late List<bool> _checkList;
  late List<int> _selectedIndex;

  bool _isOpen = false;

  @override
  void initState() {
    _checkList = List.filled(widget.number, false);
    _selectedIndex = <int>[];
    super.initState();
  }

  List<DropDownItem> generateItems() {
    var tmp = <DropDownItem>[];

    for (var i = 0; i < _checkList.length; i++) {
      tmp.add(DropDownItem(
        isChecked: _checkList[i],
        onChanged: (value) {
          setState(() {
            _checkList[i] = value!;
            if (value && !_selectedIndex.contains(i)) {
              _selectedIndex.add(i);
            } else {
              _selectedIndex.remove(i);
            }
          });
        },
      ));
    }

    return tmp;
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.start,
        mainAxisSize: MainAxisSize.min,
        children: [
          Row(
            children: [
              Expanded(
                child: Text((_selectedIndex.isEmpty)
                    ? 'Nothing Selected'
                    : _selectedIndex.join(',')),
              ),
              GestureDetector(
                onTap: () {
                  setState(() {
                    _isOpen = !_isOpen;
                  });
                },
                child: const Icon(Icons.arrow_downward),
              ),
            ],
          ),
          AnimatedOpacity(
            opacity: (_isOpen) ? 1 : 0,
            duration: const Duration(milliseconds: 300),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: generateItems(),
            ),
          )
        ],
      ),
    );
  }
}

class DropDownItem extends StatelessWidget {
  final bool isChecked;
  final Function(bool?)? onChanged;

  const DropDownItem({Key? key, this.onChanged, this.isChecked = false})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        const Expanded(child: Text('Demo item')),
        Checkbox(value: isChecked, onChanged: onChanged)
      ],
    );
  }
}

Here's how to achieve the Multiselect dropdown with DropdownButton2:以下是使用 DropdownButton2 实现多选下拉列表的方法:

final List<String> items = [
  'Item1',
  'Item2',
  'Item3',
  'Item4',
];
List<String> selectedItems = [];

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: Center(
      child: DropdownButtonHideUnderline(
        child: DropdownButton2(
          isExpanded: true,
          hint: Align(
            alignment: AlignmentDirectional.center,
            child: Text(
              'Select Items',
              style: TextStyle(
                fontSize: 14,
                color: Theme.of(context).hintColor,
              ),
            ),
          ),
          items: items.map((item) {
            return DropdownMenuItem<String>(
              value: item,
              //disable default onTap to avoid closing menu when selecting an item
              enabled: false,
              child: StatefulBuilder(
                builder: (context, menuSetState) {
                  final _isSelected = selectedItems.contains(item);
                  return InkWell(
                    onTap: () {
                      _isSelected
                              ? selectedItems.remove(item)
                              : selectedItems.add(item);
                      //This rebuilds the StatefulWidget to update the button's text
                      setState(() {});
                      //This rebuilds the dropdownMenu Widget to update the check mark
                      menuSetState(() {});
                    },
                    child: Container(
                      height: double.infinity,
                      padding: const EdgeInsets.symmetric(horizontal: 16.0),
                      child: Row(
                        children: [
                          _isSelected
                                  ? const Icon(Icons.check_box_outlined)
                                  : const Icon(Icons.check_box_outline_blank),
                          const SizedBox(width: 16),
                          Text(
                            item,
                            style: const TextStyle(
                              fontSize: 14,
                            ),
                          ),
                        ],
                      ),
                    ),
                  );
                },
              ),
            );
          }).toList(),
          //Use last selected item as the current value so if we've limited menu height, it scroll to last item.
          value: selectedItems.isEmpty ? null : selectedItems.last,
          onChanged: (value) {},
          buttonHeight: 40,
          buttonWidth: 140,
          itemHeight: 40,
          itemPadding: EdgeInsets.zero,
          selectedItemBuilder: (context) {
            return items.map(
                      (item) {
                return Container(
                  alignment: AlignmentDirectional.center,
                  padding: const EdgeInsets.symmetric(horizontal: 16.0),
                  child: Text(
                    selectedItems.join(', '),
                    style: const TextStyle(
                      fontSize: 14,
                      overflow: TextOverflow.ellipsis,
                    ),
                    maxLines: 1,
                  ),
                );
              },
            ).toList();
          },
        ),
      ),
    ),
  );
}

Also, I've added it as an example to the package doc "Example 4" so you can get back to it later.此外,我已将其作为示例添加到 package 文档“示例 4”中,以便您稍后可以返回。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM