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

A Flutter package for selecting single or multiple items from a list or grid

Items Selector #

Group 7


Introduction #

This package provides a flexible and customizable solution for selecting items from a list. It supports both single and multi-selection modes, as well as the ability to define initial items (either fixed and non-selectable or selectable). The package offers versatile display options, including scrollable lists (horizontally or vertically), grid views, and wrap-based layouts for dynamic, multi-line item arrangements. Additionally, it is fully generic and supports all data types, making it adaptable to various use cases.


Features #

  • Supports all primitive data types (e.g., int, String, etc.), enums, and custom classes.
  • Built-in state management handled by the package.
  • Provides both single-select and multi-select options.
  • Fully customizable widgets for selected and unselected states.
  • Displays scrollable lists horizontally or vertically.
  • Supports grid view and wrap-based layouts for flexible item arrangement.
  • Ability to define initial items (selectable or non-selectable).
  • Animation support.

How to use #

In a terminal, located at the root of your package, run this command:

flutter pub add items_selector

Options #

SingleSelectOption #

SingleSelectOption is used within the SingleListItemSelector, SingleGridItemSelector, and SingleWrapItemSelector widgets and includes two boolean properties:

  • allowUnselectedInitialItems
    When the initialItems property is set, enabling this option allows those initial items to be unselected.

  • allowUnselectedMainItems
    Enabling this option prevents the main items from being selected.

Row Initial Items Main Items Allow Unselect Main Items Allow Unselect Initial Items Image
1 Y Y Y Y 1
2 Y Y Y N 5
3 Y Y N Y 9
4 Y Y N N 13
5 N Y N N 14

MultiSelectOption #

MultiSelectOption is used within the MultiListItemSelector, MultiGridItemSelector, and MultiWrapItemSelector widgets and includes two properties:

  • allowUnselectedInitialItems
    When the initialItems property is set, enabling this option allows those initial items to be unselected.

  • maxItems
    Defines the maximum number of items that can be selected.

Row Initial Items Main Items Allow Unselect Initial Items Max Items Image
1 Y Y Y Y 6
2 Y Y N Y 5
3 N Y N Y 4
4 Y Y Y N 3
5 Y Y N N 2
6 N Y N N 1

Widgets #

ListSelector, GridSelector, and WrapSelector provide a flexible solution for selecting items from a collection, supporting both single and multi-selection modes.

🔹 Common Properties (Available in All Widgets) #

  • items → Defines the available list of items.
  • builder → Creates custom widgets for selected and unselected states via selectedItem and unSelectedItem.
  • selectedItems → Returns the list of selected items when a selection is made.
  • initialItems (optional) → Allows specifying pre-selected items at initialization.
  • hasLongPress (optional) → Enables selection using a long press instead of a regular tap. Default is false.
  • options → Defines selection behavior and supports both SingleSelectOption and MultiSelectOption.

🔹 Layout-Specific Properties #

  • wrapConfiguration (only for WrapSelector) → Encapsulates Wrap-specific properties such as alignment, spacing, runSpacing, etc.
  • listConfiguration (only for ListSelector) → Provides greater flexibility by allowing access to ListView properties such as scrolling behavior, physics, controllers, and other customizable options.
  • direction (only for ListSelector) → Defines the layout direction (Axis.horizontal or Axis.vertical). Default is Axis.horizontal.
  • gridConfiguration (only for GridSelector) → Determines the grid behavior and must be set to one of the following configurations:
    • BuilderConfiguration → For GridSelector.builder, similar to GridView.builder.
    • CountConfiguration → For GridSelector.count, similar to GridView.count.
    • ExtentConfiguration → For GridSelector.extent, similar to GridView.extent.

⚙️ Selection Behavior #

  • All Widgets (ListSelector, GridSelector, WrapSelector) → Use a unified options parameter, which supports:
    • SingleSelectOption
      • allowUnselectInitialItems → Controls if initial items can be unselected.
      • allowUnselectMainItems → Determines if main items can be unselected.
    • MultiSelectOption
      • allowUnselectInitialItems → Controls if initial items can be unselected.
      • maxItems → Limits the number of selectable items.

🖼️ Layout Differences #

  • 📜 List-based WidgetListSelector uses ListView for rendering items.
    • Provides two named constructors:
      • ListSelector.builder → Uses a builder function to generate items dynamically.
      • ListSelector.separated → Requires an additional separatorBuilder parameter to define separators between items.
  • 🔲 Grid-based WidgetGridSelector provides three named constructors:
    • GridSelector.builder → Uses a builder function to create grid items dynamically.
    • GridSelector.count → Uses a fixed number of columns.
    • GridSelector.extent → Uses a maximum cross-axis extent for items.
    • Requires a corresponding GridConfiguration (BuilderConfiguration, CountConfiguration, or ExtentConfiguration).
  • 🔀 Wrap-based WidgetWrapSelector provides a flexible item arrangement with automatic line breaks.
    • It has a single constructor and does not use named constructors.



ListSelector #

          ListSelector<YourDataType>.builder(
            items: yourListOfItems,
            direction: Axis.horizontal, // Set to Axis.horizontal or Axis.vertical based on layout preference
            options: SingleSelectOptions(), // Can be SingleSelectOptions() or MultiSelectOptions() based on your requirement
            listConfiguration: ListConfiguration(
              shrinkWrap: true,
              // You can also pass other ListView properties like physics, controller, etc.
            ),
            selectedItems: (List<YourDataType> selectedItems, _) {
              debugPrint(selectedItems.toString());
            },
            builder: (_, index) {
              return ItemSelector(
                selectedItem: yourDesiredWidget(),
                unSelectedItem: yourDesiredWidget(),
              );
            },
          )

        // Use ListSelector.separated if you need separators between items
          ListSelector<YourDataType>.separated(
            items: yourListOfItems,
            direction: Axis.horizontal, // Set to Axis.horizontal or Axis.vertical based on layout preference
            options: MultiSelectOptions(), // Can be SingleSelectOptions() or MultiSelectOptions() based on your requirement
            listConfiguration: ListConfiguration(
              shrinkWrap: true,
              // You can also pass other ListView properties like physics, controller, etc.
            ),
            selectedItems: (List<YourDataType> selectedItems, _) {
              debugPrint(selectedItems.toString());
            },
            separatorBuilder: (_, index) {
              return yourDesiredWidget();
            },
            builder: (_, index) {
              return ItemSelector(
                selectedItem: yourDesiredWidget(),
                unSelectedItem: yourDesiredWidget(),
              );
            },
          )



GridSelector #

           GridSelector<yourDataType>.builder(
              items: integerItems,
              // Can be SingleSelectOptions() or MultiSelectOptions() based on your requirement
              // options: SingleSelectOptions(),  // Default is SingleSelectOptions
              builderConfiguration: BuilderConfiguration(
                // You can also pass other GridView.builder properties like physics, controller, etc.
                gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
                  maxCrossAxisExtent: 120.0,
                  crossAxisSpacing: 10.0,
                  mainAxisSpacing: 10.0,
                ),
                shrinkWrap: true,
              ),
              selectedItems: (List<yourDataType> selectedItems, _) {
                debugPrint(selectedItems.toString());
              },
              builder: (_, index) {
                return ItemSelector(
                  selectedItem: yourDesireWidget(),
                  unSelectedItem: yourDesireWidget(),
                );
              },
            ),

           GridSelector<yourDataType>.count(
              items: integerItems,
              // Can be SingleSelectOptions() or MultiSelectOptions() based on your requirement
              // options: MultiSelectOptions(),  // Default is SingleSelectOptions
              countConfiguration: CountConfiguration(
                // You can also pass other GridView.count properties like physics, controller, etc.
                crossAxisCount: 3,
                shrinkWrap: true,
              ),
              selectedItems: (List<yourDataType> selectedItems, _) {
                debugPrint(selectedItems.toString());
              },
              builder: (_, index) {
                return ItemSelector(
                  selectedItem: yourDesireWidget(),
                  unSelectedItem: yourDesireWidget(),
                );
              },
            )

          GridSelector<yourDataType>.extent(
              items: integerItems,
              // Can be SingleSelectOptions() or MultiSelectOptions() based on your requirement
              // options: MultiSelectOptions(),  // Default is SingleSelectOptions
              extentConfiguration: ExtentConfiguration(
                // You can also pass other GridView.extent properties like physics, controller, etc.
                maxCrossAxisExtent: 150,
                mainAxisSpacing: 10,
                crossAxisSpacing: 10,
                shrinkWrap: true,
              ),

              selectedItems: (List<yourDataType> selectedItems, _) {
                debugPrint(selectedItems.toString());
              },
              builder: (_, index) {
                return ItemSelector(
                  selectedItem: yourDesireWidget(),
                  unSelectedItem: yourDesireWidget(),
                );
              },
            )


WrapSelector #

       WrapSelector<yourDataType>(
          items: integerItems,
          // Can be SingleSelectOptions() or MultiSelectOptions() based on your requirement
          // options: MultiSelectOptions(),  // Default is SingleSelectOptions
          wrapConfiguration: WrapConfiguration(
            // You can also pass other wrap properties like runAlignment, crossAxisAlignment, etc.
            spacing: 10,
            runSpacing: 20.0,
          ),
          selectedItems: (List<yourDataType> selectedItems, _) {
            debugPrint(selectedItems.toString());
          },
          builder: (_, index) {
            return ItemSelector(
              selectedItem: yourDesireWidget(),
              unSelectedItem: yourDesireWidget(),
            );
          },
        )



Examples #

Widget Example
ListSelector code
GridSelector code
WrapSelector code

Options Example
SingleSelectOptions code
MultiSelectOptions code


⚠️ Troubleshooting #

Issue: initialItems Not Working for Custom Classes #

If you use a custom class as the item type and set the initialItems property, you might notice that the initial items are not selected when the app runs. This happens because Dart uses reference equality by default, meaning it does not automatically recognize two objects as equal even if their properties have the same values.

✅ Solution 1: Override == Operator and hashCode #

To ensure Dart correctly identifies equal objects, override the equality (==) operator and hashCode in your custom class:

class CustomItem {
  final int id;
  final String name;

  CustomItem(this.id, this.name);

  @override
  bool operator ==(Object other) =>
          identical(this, other) || (other is CustomItem && other.id == id && other.name == name);

  @override
  int get hashCode => id.hashCode ^ name.hashCode;
}

✅ Solution 2: Use the equatable Package #

Instead of manually overriding == and hashCode, you can use the equatable package to simplify equality checks.

1️⃣ Add equatable to your dependencies:

flutter pub add equatable

2️⃣ Modify your custom class to extend equatable:

import 'package:equatable/equatable.dart';

class CustomItem extends Equatable {
  final int id;
  final String name;

  const CustomItem(this.id, this.name);

  @override
  List<Object> get props => [id, name];
}

With Equatable, Dart will automatically handle equality comparisons, ensuring initialItems work correctly! 🎯

15
likes
0
points
23
downloads

Publisher

unverified uploader

Weekly Downloads

A Flutter package for selecting single or multiple items from a list or grid

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter

More

Packages that depend on items_selector