how get selected index of multiple ExpansionTile in flutter

1k views Asked by At

how get selected index of multiple ExpansionTile in flutter ? i need sidebar menu with multiple expansiontile and listtile. how can i get selected index to change selected color menu with provider or bloc ?

enter image description here

   children: [
              ExpansionTile(
                title: Text('main a'),
                children: [
                  ListTile(
                    title: Text('a1'),
                  ),
                  ListTile(
                    title: Text('a2'),
                  ),
                  ExpansionTile(
                    title: Text('a3'),
                    children: [
                      ListTile(
                        title: Text('a31'),
                      ),
                      ListTile(
                        title: Text('a32'),
                      ),
                      ListTile(
                        title: Text('a32'),
                      ),
                    ],
                  ),
                ],
              ),
              ExpansionTile(
                title: Text('main b'),
                children: [
                  ListTile(
                    title: Text('b1'),
                  ),
                  ListTile(
                    title: Text('b2'),
                  ),
                  ListTile(
                    title: Text('b3'),
                  ),
                ],
              ),
            ],
3

There are 3 answers

0
Md. Yeasin Sheikh On

You can use onTap from ListTile, and create state variables to hold selected item. Like here I am using String. Based on your data, creating model class or map might be better choice.

  String? aValue;

  ....

  ExpansionTile(
            title: Text('main a'),
            children: [
              ListTile(
                title: Text('a1'),
                onTap: () {
                  aValue = "a1";
                  setState(() {});
                },
              ),     
2
Shashank Deepak On

You can use a ListView to contain the ExpansionTile widgets and a ListTile widgets. Then you can use a currentIndex variable to keep track of the index of the currently selected menu item. You can use a Provider or BLoC to manage the currentIndex variable and to notify the widget tree when the value of currentIndex changes.

Here is the full code

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => MenuModel(),
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('ExpansionTile Demo'),
      ),
      body: MenuList(),
    );
  }
}

class MenuList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final model = Provider.of<MenuModel>(context);
    return ListView(
      children: <Widget>[
        ExpansionTile(
          title: Text('Menu 1'),
          children: <Widget>[
            ListTile(
              title: Text('Menu 1.1'),
              onTap: () {
                model.updateIndex(0);
              },
              selected: model.currentIndex == 0,
            ),
            ListTile(
              title: Text('Menu 1.2'),
              onTap: () {
                model.updateIndex(1);
              },
              selected: model.currentIndex == 1,
            ),
          ],
        ),
        ExpansionTile(
          title: Text('Menu 2'),
          children: <Widget>[
            ListTile(
              title: Text('Menu 2.1'),
              onTap: () {
                model.updateIndex(2);
              },
              selected: model.currentIndex == 2,
            ),
            ListTile(
              title: Text('Menu 2.2'),
              onTap: () {
                model.updateIndex(3);
              },
              selected: model.currentIndex == 3,
            ),
          ],
        ),
      ],
    );
  }
}

class MenuModel with ChangeNotifier {
  int _currentIndex = 0;

  int get currentIndex => _currentIndex;

  void updateIndex(int index) {
    _currentIndex = index;
    notifyListeners();
  }
}

0
Anil Karaniya On

This is a hassle to dynamically change the color of the ListTile() which have two different parent widget but with some extra code, you can do the same.


Full Code

// You can also use `Map` but for the sake of simplicity I'm using two separate `List`.
  final List<String> _parentlist1 = ["a1", "a2"];
  final List<String> _childOfParentlist1 = ["a31", "a32", "a34"];
  final List<bool> _isSelectedForParentList1 = List.generate(
      2,
      (i) =>
          false); // Fill it with false initially and this list for all the textList
  final List<bool> _isSelectedForChildOfParentList1 =
      List.generate(2, (i) => false);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ExpansionTile(
        title: const Text('main a'),
        children: [
          ListView.builder(
            itemBuilder: (_, i) {
              return ListTile(
                tileColor: _isSelectedForParentList1[i]
                    ? Colors.blue
                    : null, // If current item is selected show blue color
                title: Text(_parentlist1[i]),
                onTap: () => setState(() => _isSelectedForParentList1[i] =
                    !_isSelectedForParentList1[i]), // Reverse bool value
              );
            },
          ),
          ExpansionTile(
            title: const Text('a3'),
            children: [
              ListView.builder(
                itemBuilder: (_, i) {
                  return ListTile(
                    tileColor: _isSelectedForChildOfParentList1[i]
                        ? Colors.blue
                        : null, // If current item is selected show blue color
                    title: Text(_childOfParentlist1[i]),
                    onTap: () => setState(() =>
                        _isSelectedForChildOfParentList1[i] =
                            !_isSelectedForChildOfParentList1[
                                i]), // Reverse bool value
                  );
                },
              ),
            ],
          ),
        ],
      ),
    );
  }