Search code examples
flutterdartwidgetflutter-dependenciesflutter-windows

Flutter Search Bar with ListView with Checkboxes


I want to create a widget like this. This contains the Textfield, Once type something in the field, It will be sorting the list and show the results below the field. The result list shown below can also have a checkbox field to select multiple items from the result. Is there any built-in flutter widget that can be useful for this case? Or any other package to achieve this.

Following is the screenshot for reference.

enter image description here

I tried with RawAutoComplete widget.

Here is the code.

   class SearchBarDemo extends StatelessWidget {
      const SearchBarDemo({super.key});
    
      static List<String> suggestons = [
        "USA",
        "UK",
        "Uganda",
        "Uruguay",
        "United Arab Emirates"
      ];
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: RawAutocomplete(
            optionsBuilder: (textEditingValue) {
              if (textEditingValue.text == '') {
                return const Iterable<String>.empty();
              } else {
                List<String> matches = <String>[];
                matches.addAll(suggestons);
    
                matches.retainWhere((s) {
                  return s
                      .toLowerCase()
                      .contains(textEditingValue.text.toLowerCase());
                });
                return matches;
              }
            },
            fieldViewBuilder:
                (context, textEditingController, focusNode, onFieldSubmitted) {
              return TextField(
                decoration: InputDecoration(
                  border: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(7),
                  ),
                  hintText: 'Search',
                  contentPadding: EdgeInsets.symmetric(
                      vertical: 8,
                      horizontal: 4), // EdgeInsets.only(top: 8, left: 5),
                  prefixIcon: Container(
                    margin: EdgeInsets.symmetric(vertical: 8, horizontal: 4),
                    decoration: BoxDecoration(
                      shape: BoxShape.rectangle,
                      border: Border(
                        right: BorderSide(
                          color: Colors.grey.shade400,
                        ),
                      ),
                    ),
                    child: Icon(
                      Icons.search,
                      color: Colors.grey.shade400,
                    ),
                  ),
                ),
                controller: textEditingController,
                focusNode: focusNode,
                onSubmitted: (String value) {},
              );
            },
            onSelected: (selection) {},
            optionsViewBuilder: (context, onSelected, options) {
              return Material(
                child: SingleChildScrollView(
                  child: Column(
                    children: options.map((opt) {
                      return InkWell(
                        onTap: () {
                          onSelected(opt);
                        },
                        child: Column(
                          children: [
                            Container(
                              height: 50,
                              width: 250,
                              alignment: Alignment.topLeft,
                              child: Card(
                                child: SizedBox(
                                  child: ListTile(
                                    title: Row(
                                      mainAxisAlignment:
                                          MainAxisAlignment.spaceBetween,
                                      children: [
                                        Text(
                                          opt,
                                          style: TextStyle(fontSize: 12),
                                        ),
                                        Transform.scale(
                                          scale: 0.8,
                                          child: Checkbox(
                                            value: false,
                                            onChanged: (val) {},
                                          ),
                                        ),
                                      ],
                                    ),
                                  ),
                                ),
                              ),
                            ),
                          ],
                        ),
                      );
                    }).toList(),
                  ),
                ),
              );
            },
          ),
        );
      }
    }

Output of the above code is: It covers the whole screen and show the result content in center.

enter image description here


Solution

  • You can customize the filter logic. Also you may like SearchDelegate-class

    
    class SearchBarDemo extends StatefulWidget {
      const SearchBarDemo({super.key});
    
      @override
      State<SearchBarDemo> createState() => _SearchBarDemoState();
    }
    
    class _SearchBarDemoState extends State<SearchBarDemo> {
      static List<String> suggestons = [
        "USA",
        "UK",
        "Uganda",
        "Uruguay",
        "United Arab Emirates"
      ];
    
      List<String> filterItems = [];
      List<String> checkedItems = [];
    
      late final TextEditingController controller = TextEditingController()
        ..addListener(() {
          /// filter logic will be here
          final text = controller.text.trim();
          filterItems = suggestons
              .where(
                  (element) => element.toLowerCase().startsWith(text.toLowerCase()))
              .toList();
    
          setState(() {});
        });
    
      @override
      void dispose() {
        controller.dispose();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
            body: Column(
          children: [
            CupertinoTextField(
              controller: controller,
            ),
            Expanded(
              child: ListView.builder(
                  itemCount: filterItems.length,
                  itemBuilder: (context, index) {
                    final bool isChecked =
                        checkedItems.contains(filterItems[index]);
                    return CheckboxListTile(
                      value: isChecked,
                      title: Text("${filterItems[index]}"),
                      onChanged: (value) {
                        if (isChecked) {
                          checkedItems.remove(filterItems[index]);
                        } else {
                          checkedItems.add(filterItems[index]);
                        }
                        setState(() {});
                      },
                    );
                  }),
            ),
          ],
        ));
      }
    }