Управление плитками расширения во Flutter: открытие по одной

В Flutter виджет Expansion Tile предоставляет удобный способ создания расширяемых и сворачиваемых плиток в вашем приложении. По умолчанию одновременно можно открыть несколько плиток расширения. Однако в некоторых сценариях вам может потребоваться запретить пользователю открывать только одну плитку расширения за раз. В этой статье мы рассмотрим различные методы достижения такого поведения во Flutter, а также приведем примеры кода.

Метод 1: ExpansionPanelList
Виджет ExpansionPanelList позволяет создать список расширяемых панелей. Обернув виджеты ExpansionTile в виджеты ExpansionPanel, вы можете включить возможность открытия только одной панели за раз. Вот пример:

ExpansionPanelList(
  elevation: 1,
  expandedHeaderPadding: EdgeInsets.zero,
  children: List.generate(
    items.length,
    (index) => ExpansionPanel(
      headerBuilder: (context, isExpanded) {
        return ListTile(
          title: Text('Panel ${index + 1}'),
        );
      },
      body: ListTile(
        title: Text('Content for Panel ${index + 1}'),
      ),
      isExpanded: selectedItemIndex == index,
    ),
  ),
  expansionCallback: (index, isExpanded) {
    setState(() {
      selectedItemIndex = isExpanded ? null : index;
    });
  },
)

Метод 2: IndexedStack
Виджет IndexedStack позволяет размещать несколько виджетов друг над другом и отображать только по одному в зависимости от индекса. Используя виджет IndexedStack для упаковки виджетов ExpansionTile и управления индексом, вы можете добиться желаемого поведения. Вот пример:

int selectedItemIndex = -1;
ListView.builder(
  itemCount: items.length,
  itemBuilder: (context, index) {
    return GestureDetector(
      onTap: () {
        setState(() {
          selectedItemIndex = index == selectedItemIndex ? -1 : index;
        });
      },
      child: IndexedStack(
        index: index == selectedItemIndex ? 1 : 0,
        children: [
          ListTile(
            title: Text('Panel ${index + 1}'),
          ),
          ListTile(
            title: Text('Content for Panel ${index + 1}'),
          ),
        ],
      ),
    );
  },
)

Метод 3: настраиваемое управление состоянием
Если вы предпочитаете использовать собственное решение для управления состоянием, вы можете создать отдельный класс для управления состоянием плиток расширения. Вот пример:

class ExpansionTileManager {
  int selectedItemIndex = -1;
  void toggle(int index) {
    selectedItemIndex = selectedItemIndex == index ? -1 : index;
  }
  bool isExpanded(int index) {
    return selectedItemIndex == index;
  }
}
ExpansionTileManager manager = ExpansionTileManager();
ListView.builder(
  itemCount: items.length,
  itemBuilder: (context, index) {
    return GestureDetector(
      onTap: () {
        setState(() {
          manager.toggle(index);
        });
      },
      child: ExpansionTile(
        title: Text('Panel ${index + 1}'),
        children: [
          ListTile(
            title: Text('Content for Panel ${index + 1}'),
          ),
        ],
        initiallyExpanded: manager.isExpanded(index),
      ),
    );
  },
)

Реализуя один из вышеперечисленных методов, вы можете гарантировать, что в вашем приложении Flutter одновременно будет открыта только одна плитка расширения. Независимо от того, решите ли вы использовать ExpansionPanelList, IndexedStack или собственный подход к управлению состоянием, конечный результат обеспечит лучшее взаимодействие с пользователем. Поэкспериментируйте с этими методами и выберите тот, который лучше всего соответствует требованиям вашего приложения.

Помните, что Flutter предоставляет широкий спектр возможностей для настройки внешнего вида и поведения плиток расширения, поэтому не стесняйтесь изучать официальную документацию Flutter для дальнейших улучшений.