content: import 'package:flutter/material.dart' hide ReorderableList;
  import 'package:flutter_reorderable_list/flutter_reorderable_list.dart';
  
  void main() => runApp(const MyApp());
  
  class MyApp extends StatelessWidget {
    const MyApp({Key? key}) : super(key: key);
  
    // This widget is the root of your application.
    @override
    Widget build(BuildContext context) {
      return MaterialApp(
        title: 'Flutter Rerderable List',
        theme: ThemeData(
          dividerColor: const Color(0x50000000),
          primarySwatch: Colors.blue,
        ),
        home: const MyHomePage(title: 'Flutter Reorderable List'),
      );
    }
  }
  
  class MyHomePage extends StatefulWidget {
    const MyHomePage({Key? key, required this.title}) : super(key: key);
  
    final String title;
  
    @override
    _MyHomePageState createState() => _MyHomePageState();
  }
  
  class ItemData {
    ItemData(this.title, this.key);
  
    final String title;
  
    // Each item in reorderable list needs stable and unique key
    final Key key;
  }
  
  enum DraggingMode {
    iOS,
    android,
  }
  
  class _MyHomePageState extends State<MyHomePage> {
    late List<ItemData> _items;
    _MyHomePageState() {
      _items = [];
      for (int i = 0; i < 500; ++i) {
        String label = "List item $i";
        if (i == 5) {
          label += ". This item has a long label and will be wrapped.";
        }
        _items.add(ItemData(label, ValueKey(i)));
      }
    }
  
    // Returns index of item with given key
    int _indexOfKey(Key key) {
      return _items.indexWhere((ItemData d) => d.key == key);
    }
  
    bool _reorderCallback(Key item, Key newPosition) {
      int draggingIndex = _indexOfKey(item);
      int newPositionIndex = _indexOfKey(newPosition);
  
      // Uncomment to allow only even target reorder possition
      // if (newPositionIndex % 2 == 1)
      //   return false;
  
      final draggedItem = _items[draggingIndex];
      setState(() {
        debugPrint("Reordering $item -> $newPosition");
        _items.removeAt(draggingIndex);
        _items.insert(newPositionIndex, draggedItem);
      });
      return true;
    }
  
    void _reorderDone(Key item) {
      final draggedItem = _items[_indexOfKey(item)];
      debugPrint("Reordering finished for ${draggedItem.title}}");
    }
  
    //
    // Reordering works by having ReorderableList widget in hierarchy
    // containing ReorderableItems widgets
    //
  
    DraggingMode _draggingMode = DraggingMode.iOS;
  
    @override
    Widget build(BuildContext context) {
      return Scaffold(
        body: ReorderableList(
          onReorder: _reorderCallback,
          onReorderDone: _reorderDone,
          child: CustomScrollView(
            // cacheExtent: 3000,
            slivers: <Widget>[
              SliverAppBar(
                actions: <Widget>[
                  PopupMenuButton<DraggingMode>(
                    child: Container(
                      alignment: Alignment.center,
                      padding: const EdgeInsets.symmetric(horizontal: 30.0),
                      child: const Text("Options"),
                    ),
                    initialValue: _draggingMode,
                    onSelected: (DraggingMode mode) {
                      setState(() {
                        _draggingMode = mode;
                      });
                    },
                    itemBuilder: (BuildContext context) =>
                        <PopupMenuItem<DraggingMode>>[
                      const PopupMenuItem<DraggingMode>(
                          value: DraggingMode.iOS,
                          child: Text('iOS-like dragging')),
                      const PopupMenuItem<DraggingMode>(
                          value: DraggingMode.android,
                          child: Text('Android-like dragging')),
                    ],
                  ),
                ],
                pinned: true,
                expandedHeight: 150.0,
                flexibleSpace: const FlexibleSpaceBar(
                  title: Text('Demo'),
                ),
              ),
              SliverPadding(
                  padding: EdgeInsets.only(
                      bottom: MediaQuery.of(context).padding.bottom),
                  sliver: SliverList(
                    delegate: SliverChildBuilderDelegate(
                      (BuildContext context, int index) {
                        return Item(
                          data: _items[index],
                          // first and last attributes affect border drawn during dragging
                          isFirst: index == 0,
                          isLast: index == _items.length - 1,
                          draggingMode: _draggingMode,
                        );
                      },
                      childCount: _items.length,
                    ),
                  )),
            ],
          ),
        ),
      );
    }
  }
  
  class Item extends StatelessWidget {
    const Item({
      Key? key,
      required this.data,
      required this.isFirst,
      required this.isLast,
      required this.draggingMode,
    }) : super(key: key);
  
    final ItemData data;
    final bool isFirst;
    final bool isLast;
    final DraggingMode draggingMode;
  
    Widget _buildChild(BuildContext context, ReorderableItemState state) {
      BoxDecoration decoration;
  
      if (state == ReorderableItemState.dragProxy ||
          state == ReorderableItemState.dragProxyFinished) {
        // slightly transparent background white dragging (just like on iOS)
        decoration = const BoxDecoration(color: Color(0xD0FFFFFF));
      } else {
        bool placeholder = state == ReorderableItemState.placeholder;
        decoration = BoxDecoration(
            border: Border(
                top: isFirst && !placeholder
                    ? Divider.createBorderSide(context) //
                    : BorderSide.none,
                bottom: isLast && placeholder
                    ? BorderSide.none //
                    : Divider.createBorderSide(context)),
            color: placeholder ? null : Colors.white);
      }
  
      // For iOS dragging mode, there will be drag handle on the right that triggers
      // reordering; For android mode it will be just an empty container
      Widget dragHandle = draggingMode == DraggingMode.iOS
          ? ReorderableListener(
              child: Container(
                padding: const EdgeInsets.only(right: 18.0, left: 18.0),
                color: const Color(0x08000000),
                child: const Center(
                  child: Icon(Icons.reorder, color: Color(0xFF888888)),
                ),
              ),
            )
          : Container();
  
      Widget content = Container(
        decoration: decoration,
        child: SafeArea(
            top: false,
            bottom: false,
            child: Opacity(
              // hide content for placeholder
              opacity: state == ReorderableItemState.placeholder ? 0.0 : 1.0,
              child: IntrinsicHeight(
                child: Row(
                  crossAxisAlignment: CrossAxisAlignment.stretch,
                  children: <Widget>[
                    Expanded(
                        child: Padding(
                      padding: const EdgeInsets.symmetric(
                          vertical: 14.0, horizontal: 14.0),
                      child: Text(data.title,
                          style: Theme.of(context).textTheme.titleMedium),
                    )),
                    // Triggers the reordering
                    dragHandle,
                  ],
                ),
              ),
            )),
      );
  
      // For android dragging mode, wrap the entire content in DelayedReorderableListener
      if (draggingMode == DraggingMode.android) {
        content = DelayedReorderableListener(
          child: content,
        );
      }
  
      return content;
    }
  
    @override
    Widget build(BuildContext context) {
      return ReorderableItem(
          key: data.key, //
          childBuilder: _buildChild);
    }
  }
  