expansion_tile_list 2.0.0 copy "expansion_tile_list: ^2.0.0" to clipboard
expansion_tile_list: ^2.0.0 copied to clipboard

A customizable set of expansion tiles with versatile options for styling, animations, and control over expansion behavior, while streamlining essential features for ease of use.

example/lib/main.dart

import 'dart:developer' as developer;
import 'dart:math';

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

void main() {
  runApp(const App());
}

/// A simple example of how to use the ExpansionTileList widget.
class App extends StatelessWidget {
  const App({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Expansion Tile List',
        theme: ThemeData(
          colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
          useMaterial3: true,
          expansionTileTheme: ExpansionTileThemeData(
            iconColor: Colors.black,
            textColor: Colors.black,
            // iconTheme: IconThemeData(color: Colors.black),
            backgroundColor: Colors.blueGrey.shade300,
            collapsedIconColor: Colors.white,
            collapsedTextColor: Colors.white,
            // collapsedIconTheme: IconThemeData(color: Colors.black),
            collapsedBackgroundColor: Colors.blueGrey,
          ),
        ),
        home: Scaffold(
          appBar: AppBar(
            title: const Text('Expansion Tile List Examples'),
          ),
          body: SafeArea(child: LayoutBuilder(builder:
              (BuildContext context, BoxConstraints viewportConstraints) {
            return Column(children: [
              _buildPage(context),
            ]);
          })),
        ));
  }

  Widget _buildPage(BuildContext context) {
    return Expanded(
        child: PageView(
      children: <Widget>[
        Examples.buildBasicUsage(),
        Examples.buildCustomExpansionCallback(),
        Examples.buildCustomExpansionTile(),
      ]
          .map((child) => SingleChildScrollView(child: child))
          .toList(growable: false),
    ));
  }
}

class Examples {
  static Widget buildBasicUsage() {
    return ExpansionTileList(
      itemGapSize: 8.0,
      separatorBuilder: (BuildContext context, int index) {
        return const Divider(
          height: 1.0,
          color: Colors.red,
        );
      },
      children: <ExpansionTile>[
        ..._buildChildren('basic'),
      ],
    );
  }

// With onExpansionChanged Callback
  static Widget buildCustomExpansionCallback() {
    return ExpansionTileList(
      itemGapSize: 8.0,
      children: <ExpansionTile>[
        ..._buildChildren('onExpansionChanged'),
      ],
      onExpansionChanged: (index, isExpanded) {
        developer.log('Tile $index isExpanded: $isExpanded');
      },
    );
  }

// With custom expansion tile using builder
  static Widget buildCustomExpansionTile() {
    return ExpansionTileList(
      itemGapSize: 8.0,
      children: <ExpansionTile>[
        ..._buildChildren('builder'),
      ],
      itemBuilder: (BuildContext context, int index, Widget? child) {
        return Column(
          children: <Widget>[
            child!,
            Text('Custom Divider $index',
                style: const TextStyle(color: Colors.red)),
            const Divider(
              height: 1.0,
              color: Colors.red,
            ),
          ],
        );
      },
    );
  }

// With custom separator
  static Widget buildWithCustomSeparator() {
    return ExpansionTileList(
      itemGapSize: 8.0,
      children: <ExpansionTile>[
        ..._buildChildren('separator'),
      ],
      separatorBuilder: (BuildContext context, int index) {
        return const Divider(
          height: 1.0,
          color: Colors.red,
        );
      },
    );
  }

  // With trailing icon
  static Widget buildWithTrailingIcon() {
    return ExpansionTileList(
      itemGapSize: 8.0,
      trailing: const Icon(Icons.add),
      children: <ExpansionTile>[
        ..._buildChildren('trailingIcon'),
      ],
    );
  }

  // With  trailing animation disabled
  static Widget buildWithTrailingAnimationDisabled() {
    return ExpansionTileList(
      itemGapSize: 8.0,
      trailing: const Icon(Icons.add),
      enableTrailingAnimation: false,
      children: <ExpansionTile>[
        ..._buildChildren('trailingAnimation'),
      ],
    );
  }
}

class ReorderableExamples {
  // With leading drag handle for reorderable ExpansionTileList
  static Widget buildWithLeadingDragHandle() {
    return ExpansionTileList.reorderable(
      dragHandlePlacement: DragHandlePlacement.leading,
      children: <ExpansionTile>[
        ..._buildChildren('LeadingDragHandle'),
      ],
    );
  }

  // With custom drag handle for reorderable ExpansionTileList
  static Widget buildWithCustomDragHandle() {
    return ExpansionTileList.reorderable(
      dragHandlePlacement: DragHandlePlacement.leading,
      dragHandleBuilder: (context, index) {
        return Container(
          padding: const EdgeInsets.all(8.0),
          color: Colors.blue,
          child: const Icon(Icons.drag_handle, color: Colors.white),
        );
      },
      children: <ExpansionTile>[
        ..._buildChildren('CustomDragHandle'),
      ],
    );
  }

  // With drag handle alignment  for reorderable ExpansionTileList
  static Widget buildWithDragHandleAlignment() {
    return ExpansionTileList.reorderable(
      dragHandlePlacement: DragHandlePlacement.leading,
      dragHandleAlignment: DragHandleAlignment.centerRight,
      children: <ExpansionTile>[
        ..._buildChildren('DragHandleAlignment'),
      ],
    );
  }

  // With proxy decorator
  static Widget buildWithProxyDecorator() {
    final controller = ExpansionTileListController();
    return ExpansionTileList.reorderable(
      controller: controller,
      proxyDecorator: (child, index, animation) {
        return Material(
          elevation: 6.0,
          child: child,
        );
      },
      children: <ExpansionTile>[
        ..._buildChildren('ProxyDecorator'),
      ],
    );
  }

  // With use delayed drag
  static Widget buildWithUseDelayedDrag() {
    final controller = ExpansionTileListController();
    return ExpansionTileList.reorderable(
      controller: controller,
      useDelayedDrag: true,
      children: <ExpansionTile>[
        ..._buildChildren('UseDelayedDrag'),
      ],
    );
  }
}

// Helper method to generate a list of ExpansionTiles
List<ExpansionTile> _buildChildren([String name = '']) {
  return List.generate(
      4,
      (index) => ExpansionTile(
            title: Text('Tile $index  $name'),
            children: <Widget>[
              ...List.generate(
                  6, (i) => Text('This is tile $index of $i $name')),
            ],
          ));
}

class AdvancedCustomDragHandleExample extends StatefulWidget {
  const AdvancedCustomDragHandleExample({super.key});

  @override
  State<StatefulWidget> createState() =>
      _AdvancedCustomDragHandleExampleState();
}

class _AdvancedCustomDragHandleExampleState
    extends State<AdvancedCustomDragHandleExample> {
  final controller = ExpansionTileListController();
  final ValueNotifier<(int, int)> _reorderNotifier =
      ValueNotifier((-1, -1)); // remember to dispose the ValueNotifier
  @override
  void didUpdateWidget(AdvancedCustomDragHandleExample oldWidget) {
    super.didUpdateWidget(oldWidget);
    _reorderNotifier.value = (-1, -1);
  }

  @override
  void dispose() {
    _reorderNotifier.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return ExpansionTileList.reorderable(
      enableDefaultDragHandles: false,
      controller: controller,
      dragHandlePlacement: DragHandlePlacement.leading,
      dragHandleAlignment: DragHandleAlignment.centerRight,
      dragHandleBuilder: (context, index) {
        return Container(
          padding: const EdgeInsets.all(8.0),
          color: Colors.blue,
          child: const Icon(Icons.drag_handle, color: Colors.white),
        );
      },
      onReorder: (oldIndex, newIndex) {
        _reorderNotifier.value = (
          oldIndex,
          newIndex
        ); // notify the custom drag handle of the reorder
      },
      children: <ExpansionTile>[
        ...List.generate(10, (index) {
          return ExpansionTile(
            leading: _buildCustomDragHandle(index),
            title: Text('Tile $index'),
            children: <Widget>[Text('Child $index')],
          );
        }),
      ],
    );
  }

  Widget _buildCustomDragHandle(int itemIndex) {
    Widget dragHandle(int index) {
      return ReorderableDragStartListener(
        key: PageStorageKey(index),
        index: index,
        child: const Icon(Icons.drag_handle),
      );
    }

    Widget? currentDragHandle;
    return ValueListenableBuilder<(int, int)>(
      valueListenable: _reorderNotifier,
      child: currentDragHandle,
      builder: (context, (int, int) value, child) {
        var minIndex = min(value.$1, value.$2);
        var maxIndex = max(value.$1, value.$2);
        var index = controller.currentPosition(itemIndex);
        if (minIndex < 0 || (index >= minIndex && index <= maxIndex)) {
          //only update when reorder index is within the range of oldIndex and newIndex or is -1
          currentDragHandle =
              (index == itemIndex ? child : null) ?? dragHandle(index);
        }
        return currentDragHandle ?? dragHandle(index);
      },
    );
  }
}
29
likes
150
points
663
downloads

Publisher

verified publishermonohaus.com

Weekly Downloads

A customizable set of expansion tiles with versatile options for styling, animations, and control over expansion behavior, while streamlining essential features for ease of use.

Repository (GitHub)
View/report issues

Topics

#widget #expandable #expansion #expansion-tile #expansion-tile-list

Documentation

API reference

Funding

Consider supporting this project:

buymeacoffee.com

License

BSD-3-Clause (license)

Dependencies

flutter

More

Packages that depend on expansion_tile_list