Open / close filter menu

159

The each main filter item must be controlled one by one.

  • Define List isClickedCountry variable
  • Save and load state from List isClickedCountry variable

enter image description here

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: _buildBody(),
      floatingActionButton: FloatingActionButton(
        onPressed: () {},
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }

  Widget _buildBody() {
    return FilterDialogUser();
  }
}

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

  @override
  State<FilterDialogUser> createState() => _FilterDialogUserState();
}

class _FilterDialogUserState extends State<FilterDialogUser> {
  Map<String, List<String>> filters = {};
  bool needRefresh = false;
  List<bool> isClickedCountry = List.filled(3, false);

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

  List<FilterItem> children = [
    FilterItem('Georgia', subitems: [
      FilterItem('Tbilisi'),
      FilterItem('Batumi'),
    ]),
    FilterItem('Poland', subitems: [
      FilterItem('Warsaw'),
      FilterItem('Krakow'),
      FilterItem('Wroclaw'),
    ]),
    FilterItem('Armenia', subitems: [
      FilterItem('Erevan'),
      FilterItem('Gyumri'),
    ]),
  ];

  // Building a dialog box with filters.
  @override
  Widget build(BuildContext context) {
    return SimpleDialog(
        title: const Text('Filters',
            textAlign: TextAlign.center,
            style: TextStyle(
              fontSize: 25,
              fontFamily: 'SuisseIntl',
            )),
        contentPadding: const EdgeInsets.all(16),

        // Defining parameters for filtering.
        children: [
          Column(
            children: children.map(
              (e) {
                final int index = children.indexOf(e);
                return Column(
                  children: [
                    InkWell(
                      onTap: () async {
                        setState(() {
                          isClickedCountry[index] = !isClickedCountry[index];
                        });
                      },
                      child: Row(
                        children: [
                          Checkbox(
                            value: e.selected,
                            onChanged: (value) => setState(() {
                              e.subitems.forEach((element) =>
                                  element.selected = value as bool);
                              e.selected = value as bool;
                            }),
                          ),
                          Text(e.text),
                          const Spacer(),
                          isClickedCountry[index]
                              ? const Icon(Icons.arrow_circle_up)
                              : const Icon(Icons.arrow_circle_down)
                        ],
                      ),
                    ),
                    if (e.subitems.isNotEmpty)
                      !isClickedCountry[index]
                          ? Container()
                          : Padding(
                              padding: const EdgeInsets.fromLTRB(30, 0, 0, 0),
                              child: Column(
                                children: e.subitems.map((e) {
                                  return Row(children: [
                                    Checkbox(
                                      value: e.selected,
                                      onChanged: (value) => setState(() {
                                        e.selected = value as bool;
                                      }),
                                    ),
                                    Text(e.text),
                                  ]);
                                }).toList(),
                              ),
                            )
                  ],
                );
              },
            ).toList(),
          ),
        ]);
  }
}

class FilterItem {
  final String text;
  bool selected;
  List<FilterItem> subitems;

  FilterItem(
    this.text, {
    this.selected = false,
    this.subitems = const [],
  });
}
Share:
159
Paul
Author by

Paul

Updated on January 04, 2023

Comments

  • Paul
    Paul over 1 year

    I have a code that is responsible for building a menu filter. It allows you to filter data by category and then by subcategory.

    Initially, subcategories are in a closed state, but when you click on the arrow, they can be opened. Take a look

    enter image description here

    enter image description here

    But my problem is that if I click on the arrow for any category (Country in my case), then all subcategories open at once. Take a look

    enter image description here

    It's my code

    class _FilterDialogUserState extends State<FilterDialogUser> {
      Map<String, List<String>?> filters = {};
      bool needRefresh = false;
      bool isClickedCountry = false;
    
      @override
      void initState() {
        super.initState();
        filters = widget.initialState;
      }
    
      List<FilterItem> children = [
        FilterItem('Georgia', subitems: [
          FilterItem('Tbilisi'),
          FilterItem('Batumi'),
        ]),
        FilterItem('Poland', subitems: [
          FilterItem('Warsaw'),
          FilterItem('Krakow'),
          FilterItem('Wroclaw'),
        ]),
        FilterItem('Armenia', subitems: [
          FilterItem('Erevan'),
          FilterItem('Gyumri'),
        ]),
      ];
    
      // Building a dialog box with filters.
      @override
      Widget build(BuildContext context) {
        return SimpleDialog(
            title: const Text('Filters',
                textAlign: TextAlign.center,
                style: TextStyle(
                  fontSize: 25,
                  fontFamily: 'SuisseIntl',
                )),
            contentPadding: const EdgeInsets.all(16),
    
            // Defining parameters for filtering.
            children: [
              Column(
                children: children.map(
                  (e) {
                    return Column(
                      children: [
                        InkWell(
                          onTap: () async {
                            setState(() {
                              isClickedCountry = !isClickedCountry;
                            });
                          },
                          child: Row(
                            children: [
                              Checkbox(
                                value: e.selected,
                                onChanged: (value) => setState(() {
                                  e.subitems.forEach((element) =>
                                      element.selected = value as bool);
                                  e.selected = value as bool;
                                }),
                              ),
                              Text(e.text),
                              const Spacer(),
                              isClickedCountry
                                  ? const Icon(Icons.arrow_circle_up)
                                  : const Icon(Icons.arrow_circle_down)
                            ],
                          ),
                        ),
                        if (e.subitems.isNotEmpty)
                          !isClickedCountry
                              ? Container()
                              : Padding(
                                  padding: const EdgeInsets.fromLTRB(30, 0, 0, 0),
                                  child: Column(
                                    children: e.subitems.map((e) {
                                      return Row(children: [
                                        Checkbox(
                                          value: e.selected,
                                          onChanged: (value) => setState(() {
                                            e.selected = value as bool;
                                          }),
                                        ),
                                        Text(e.text),
                                      ]);
                                    }).toList(),
                                  ),
                                )
                      ],
                    );
                  },
                ).toList(),
              ),
            ]);
      }
    }
    
    class FilterItem {
      final String text;
      bool selected;
      List<FilterItem> subitems;
    
      FilterItem(
        this.text, {
        this.selected = false,
        this.subitems = const [],
      });
    }
    

    Tell me, is it possible to change my code so that not all subcategories are opened, but only the one that the user clicks on?

  • Paul
    Paul about 2 years
    It's great solution. Thanks a lot. You helped me really