Drag Selectable ListView

A Flutter ListView that supports drag-to-select multiple items with customizable selection UI and smooth interaction.

Features

Drag Selection: Select multiple items by dragging across them
🎨 Customizable UI: Custom checkbox builders and item layouts
🎯 Flexible Selection: Support for both tap and drag selection modes
Performance Optimized: Efficient state management with Provider pattern
🎛️ Configurable: Optional haptic feedback

Demo

Demo GIF

Getting Started

Installation

Add this to your package's pubspec.yaml file:

dependencies:
  drag_selectable_listview: ^2.0.1

Then run:

flutter pub get

Complete Example

Here's a complete working example showing how to use DragSelectableListView:

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

  @override
  State<DemoPage> createState() => _DemoPageState();
}

class _DemoPageState extends State<DemoPage> {
  int itemCount = 100;
  late DragSelectableProvider provider;

  @override
  void initState() {
    super.initState();
    List<bool> initialSelection = List.generate(itemCount, (_) => false);
    provider = DragSelectableProvider(initialSelection);
  }

  void _showToast() {
    Set<int> set = {};
    for (int i = 0; i < provider.selected.length; i++) {
      if (provider.selected[i]) {
        set.add(i);
      }
    }

    // Show toast to display selected elements
    String message;
    if (set.isEmpty) {
      message = "No items selected";
    } else {
      message = "Selected items: ${set.toList().join(', ')}";
    }

    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text(message),
        duration: Duration(seconds: 2),
        behavior: SnackBarBehavior.floating,
      ),
    );
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Demo")),
      body: Column(
        children: [
          ElevatedButton(
            onPressed: () {
              _showToast();
            },
            child: Text("toast selected"),
          ),
          Expanded(
            child: DragSelectableListView(
              provider: provider,
              itemCount: itemCount,
              itemHeight: 40,
              checkboxWidth: 40,
              touchSlop: 8.0,
              itemBuilder: (context, index) {
                return GestureDetector(
                  onTap: () {
                    print(index);
                  },
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Expanded(
                        flex: 1,
                        child: Column(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: [Text("Item $index")],
                        ),
                      ),
                      Divider(height: 1),
                    ],
                  ),
                );
              },
              checkboxBuilder:
                      ({
                required bool value,
                required ValueChanged<bool?> onChanged,
              }) => Transform.scale(
                scale: 1.2,
                child: Checkbox(
                  shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(10.0),
                  ),
                  value: value,
                  onChanged: onChanged,
                ),
              ),
              onSelectionChanged: (List<bool> list) {
                //print(list);
              },
            ),
          ),
        ],
      ),
    );
  }
}

API Reference

DragSelectableListView Properties

  • provider (DragSelectableProvider): State management provider for selection logic
  • itemCount (int): Total number of items in the list
  • itemBuilder (IndexedWidgetBuilder): Builder function for list items
  • onSelectionChanged (ValueChanged<List
  • checkboxBuilder (Function): Builder for custom checkbox widgets
  • itemHeight (double): Height of each list item
  • checkboxWidth (double): Width allocated for checkbox area
  • touchSlop (double): Minimum drag distance to activate selection mode
  • enableHapticFeedback (bool): Enable/disable haptic feedback during selection

DragSelectableProvider Properties

  • selected (List
  • isSelecting (bool): Whether drag selection mode is active
  • scrollController (ScrollController): Controller for list scrolling

Selection Behavior

  • Tap Selection: Tap individual checkboxes to toggle selection
  • Drag Selection: Press and drag across items to select/deselect ranges
    • Important: Drag selection only activates when gesture starts within checkbox area (defined by checkboxWidth)
    • Gestures starting outside checkbox area trigger normal list scrolling
  • Selection Toggle: Drag selection toggles items (selected ↔ deselected)
  • Visual Feedback: Selection changes are immediately reflected in the UI

Testing

This package includes comprehensive tests covering:

  • Widget rendering and layout
  • Selection state management
  • Provider functionality
  • Parameter validation
  • Edge cases and boundary conditions
  • Resource cleanup and disposal

The test suite includes:

  • Unit Tests: 17 tests covering all provider functionality
  • Test Coverage: 100% coverage of core components
  • Documentation: Complete testing guide in TESTING.md

Run tests with:

flutter test

Bug Reports

Please file bug reports with:

  • Clear description of the issue
  • Steps to reproduce
  • Expected vs actual behavior
  • Flutter version and device information

What's New in v2.0.0

🚀 Major Improvements

  • Enhanced State Management: Improved Provider pattern implementation
  • Better Performance: Optimized widget rebuilds with selective listening
  • Comprehensive Testing: Added complete test suite with 17 tests

🔧 Breaking Changes

  • Updated API to use DragSelectableProvider for state management
  • Changed onSelectionChanged callback to use List<bool> instead of Set<int>
  • Improved constructor parameter validation

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support

If you have any questions or need help, please open an issue on GitHub.


Made with ❤️ by the Flutter community