简体   繁体   中英

How do I make a ReorderableListView ListTile draggable on button/icon press for Flutter?

So I saw the ReorderableListView demo and saw that they had the

"secondary: const Icon(Icons.drag_handle)"

but looking at the reorderable_list.dart file, I noticed that the entire list was draggable on LongPressDraggable anyway [line 424]. So how can I explicitly make changes to either the source code or my own, in order to properly make the icon an actual drag handle?

CheckboxListTile(
      key: Key(item.value),
      isThreeLine: true,
      value: item.checkState ?? false,
      onChanged: (bool newValue) {
        setState(() {
          item.checkState = newValue;
        });
      },
      title: Text('This item represents ${item.value}.'),
      subtitle: secondary,
      secondary: const Icon(Icons.drag_handle),  // Make this Icon drag source
    );

Thanks

I think the Icon(Icons.drag_handle) it's just for the looks there, to drag the item in a ReorderableListView you have to long press it.

You can use flutter_reorderable_list and achieve that. As you can see in its demo, this plugin works just the way you want to.

However, it works quite differently of ReorderableListView , the code change can be a bit overwhelming. I created a Widget to simplify that switch, the widget is here and its demo is here .

Take a look and use it if it fits your use case.

2021/05/29

As an update of the answer, there's already a customizable handler for the ReorderableListView :

With the recent refactoring of the ReorderableListView (PRs: #74299 and #74697), we have added automatic drag handles when running on the desktop (with a buildDefaultDragHandles property to turn it off). If this isn't what you want, you can add your own drag handle as a widget to each of your items with something like:

ReorderableDragStartListener(
  index: index,
  child: const Icon(Icons.drag_handle),
),

You can check the details here: https://github.com/flutter/flutter/issues/46805

DragHandles are hidden on mobile platforms by default. However, you can add a drag Handle in a ReorderableListView using ReorderableDragStartListener in your List item.

 ListTile(
   key: Key('$index'),
   tileColor: _items[index].isOdd ? oddItemColor : evenItemColor,
   title: Text('Item ${_items[index]}'),
   trailing: ReorderableDragStartListener(
      key: ValueKey<int>(_items[index]),
      index: index,
      child: const Icon(Icons.drag_handle),
   ),
),

Output

在此处输入图像描述

complete code sample

import 'dart:ui';

import 'package:flutter/material.dart';

void main() => runApp(const ReorderableApp());

class ReorderableApp extends StatelessWidget {
  const ReorderableApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('ReorderableListView Sample')),
        body: const ReorderableExample(),
      ),
    );
  }
}

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

  @override
  State<ReorderableExample> createState() => _ReorderableExampleState();
}

class _ReorderableExampleState extends State<ReorderableExample> {
  final List<int> _items = List<int>.generate(50, (int index) => index);

  @override
  Widget build(BuildContext context) {
    final ColorScheme colorScheme = Theme.of(context).colorScheme;
    final Color oddItemColor = colorScheme.secondary.withOpacity(0.05);
    final Color evenItemColor = colorScheme.secondary.withOpacity(0.15);
    final Color draggableItemColor = colorScheme.secondary;

    Widget proxyDecorator(
        Widget child, int index, Animation<double> animation) {
      return AnimatedBuilder(
        animation: animation,
        builder: (BuildContext context, Widget? child) {
          final double animValue = Curves.easeInOut.transform(animation.value);
          final double elevation = lerpDouble(0, 6, animValue)!;
          return Material(
            elevation: elevation,
            color: draggableItemColor,
            shadowColor: draggableItemColor,
            child: child,
          );
        },
        child: child,
      );
    }

    return ReorderableListView(
      padding: const EdgeInsets.symmetric(horizontal: 40),
      children: <Widget>[
        for (int index = 0; index < _items.length; index += 1)
          ListTile(
            key: Key('$index'),
            tileColor: _items[index].isOdd ? oddItemColor : evenItemColor,
            title: Text('Item ${_items[index]}'),
            trailing: ReorderableDragStartListener(
              key: ValueKey<int>(_items[index]),
              index: index,
              child: const Icon(Icons.drag_handle),
            ),
          ),
      ],
      onReorder: (int oldIndex, int newIndex) {
        setState(() {
          if (oldIndex < newIndex) {
            newIndex -= 1;
          }
          final int item = _items.removeAt(oldIndex);
          _items.insert(newIndex, item);
        });
      },
    );
  }
}

Originally posted here: https://github.com/flutter/flutter/issues/25065#issuecomment-1381324936

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM