Is it possible to disable reordering a single item in a reorderable listview in flutter?

4.6k views Asked by At

I am trying to create a ListView that meets the following criteria:

  1. The items in the ListView are categorized into sections with headers for each section
  2. The items can be dragged from one section to another
  3. The section headers are not draggable

This would easy to accomplish if ReorderableListView allowed you to disable a ListTile from being dragged & dropped (in other words, I would be able to create the headers as ListTile items in the ListView and disable dragging and dropping on only them while still allowing everything else to be dragged & dropped), but I can't figure out how. Any tips?

6

There are 6 answers

0
takudzw_M On

This is another workaround.

Wrap the widget you don't want to be moved in a GestureDetector, then override the onLongPress.

 return GestureDetector(
                                  onLongPress: () {},
                                  key: ValueKey(index),
                                  child: Column(
                                      children: List.generate(
                                          3,
                                          (index) => ListTile(
                                              title: Text("TItle test")))),
                                );

Check this https://github.com/hanshengchiu/reorderables/issues/89#:~:text=movable%20widgets%20in%3A-,GestureDetector(%0A%20%20%20%20%20%20onLongPress%3A%20()%20%7B%7D%2C%20//%20Override%20onLongPress%20to%20make%20item%20unmovable.%0A%20%20%20%20%20%20child%3A%20...%0A),-6 for the full discussion

2
Wagner Maciel On

Just discovered the AbsorbPointer and IgnorePointer classes.

0
wujek On

You can prevent moving the headers with AbsortPointer etc. as you mentioned, but if the other items are moved into a place that you don't want to allow, you can simply check for this in the onReorder callback and not update the underlying model, so when the user drops the item it will get back to its original place. E.g. if the user tries moving any movable item to be placed before the first header, you detect this (newIndex == 0) and return early.

0
anjo jy On

The reorderable list wrap with AbsorbPointer widget

Use AbsorbPointer to disable widgets

 AbsorbPointer(
            absorbing: countList.length <= 1 ? true : false,
            child: ReorderableListView(
                shrinkWrap: true,
                buildDefaultDragHandles: false,
                dragStartBehavior: DragStartBehavior.down,
                physics: const NeverScrollableScrollPhysics(),
                children: <Widget>[
                  for (var i = 0; i < countList.length; i++)
                    Card(
                      elevation: 0,
                      color: customColors().backgroundPrimary,
                      key: ValueKey(
                          countList[i].Name),
                      child: Container(
                        child:Text("Demo")
                      ),
                    ),
                ],
                onReorder:onReoder),
          ),
0
Viktor Kadza Jr. On

You can add a some type of nonreorderable bool field to tiles , and check it when onReorder is called, and just skip the index change, or do same extra logic for that particular case.

1
Alexander Melnikov On

You can use ReorderableDragStartListener.

Wrap the sections that need to be non-reorderable with it and pass enabled: false like so:

class HeaderSection extends StatelessWidget {
  const HeaderSection({
    Key? key,
    required this.index,
  }) : super(key: key);

  final int index;

  @override
  Widget build(BuildContext context) {
    return ReorderableDragStartListener(
      index: index,
      enabled: false,
      child: const Text('This header can not be dragged'),
    );
  }
} 

There is also ReorderableDelayedDragStartListener for cases where you want to use long-press to begin reordering.