简体   繁体   中英

How to create space between ListTiles in Flutter ReorderableListView

I have a ReorderableListView who looks like this:

在此处输入图像描述

And I would like it to have space between his ListTile like in the ListView.separated below:

在此处输入图像描述

The problem is that I don't want to use ListView.separated because you can't drag and drop ListTiles with it.

Update Solution found:

I used Varun's answer below of wrapping my ListTile in a Column, but instead of using a SizedBox I used a Container to be able to change the color of the space from white to my background color:

Container(
          height: 5.0,
          color: MyColors.myBackgroundColor
        )

You could just wrap your listTile with a padding at the bottom as "divider" it might not be ideal as the padding would be part of the widget, whic would be visible when dragging.

在此处输入图像描述

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  static const String _title = 'Flutter Code Sample';

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: _title,
      home: Scaffold(
        appBar: AppBar(title: const Text(_title)),
        body: const MyStatefulWidget(),
      ),
    );
  }
}

class MyStatefulWidget extends StatefulWidget {
  const MyStatefulWidget({Key? key}) : super(key: key);

  @override
  State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}

class _MyStatefulWidgetState extends State<MyStatefulWidget> {
  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.primary.withOpacity(0.05);
    final Color evenItemColor = colorScheme.primary.withOpacity(0.15);

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


Adding the space as a non reorderable widget does not seem possible with ReorderableListView even adding dummy items interleaving the ListTiles with AbsorbPointer still renders them reorderable. So the method above is at least doable在此处输入图像描述

      children: <Widget>[
        for (int index = 0; index < _items.length; index++)
          if (index.isOdd)
            ListTile(
              key: Key('$index'),
              tileColor: _items[index].isOdd ? oddItemColor : evenItemColor,
              title: Text('Item ${_items[index]}'),
            )
          else if (index.isEven)
            AbsorbPointer(
              key: Key('$index'),
              child: SizedBox.square(
                key: Key('$index'),
                dimension: 40,
              ),
            ),
      ],

Wrap your ListTile in a column and use SizedBox to separate list items. Use key in column, not inside ListTile.

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  static const String _title = 'Flutter Code Sample';

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: _title,
      home: Scaffold(
        appBar: AppBar(title: const Text(_title)),
        body: const MyStatefulWidget(),
      ),
    );
  }
}

class MyStatefulWidget extends StatefulWidget {
  const MyStatefulWidget({Key? key}) : super(key: key);

  @override
  State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}

class _MyStatefulWidgetState extends State<MyStatefulWidget> {
  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.primary.withOpacity(0.05);
    final Color evenItemColor = colorScheme.primary.withOpacity(0.15);

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

This is works like a mixture ViewList.separated and ReorderableList

     import 'dart:math';

import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';

class CustomReorderableListView extends ReorderableListView {
  CustomReorderableListView.separated({
    Key? key,
    required IndexedWidgetBuilder itemBuilder,
    required IndexedWidgetBuilder separatorBuilder,
    required int itemCount,
    required ReorderCallback onReorder,
    double? itemExtent,
    Widget? prototypeItem,
    ReorderItemProxyDecorator? proxyDecorator,
    bool buildDefaultDragHandles = true,
    EdgeInsets? padding,
    Widget? header,
    Axis scrollDirection = Axis.vertical,
    bool reverse = false,
    ScrollController? scrollController,
    bool? primary,
    ScrollPhysics? physics,
    bool shrinkWrap = false,
    double anchor = 0.0,
    double? cacheExtent,
    DragStartBehavior dragStartBehavior = DragStartBehavior.start,
    ScrollViewKeyboardDismissBehavior keyboardDismissBehavior =
        ScrollViewKeyboardDismissBehavior.manual,
    String? restorationId,
    Clip clipBehavior = Clip.hardEdge,
  }) : super.builder(
    key: key,
    itemCount: max(0, itemCount * 2 - 1),
    itemBuilder: (BuildContext context, int index) {
      if (index % 2 == 1) {
        final separator = separatorBuilder.call(context, index);

        if (separator.key == null) {
          return KeyedSubtree(
            key: ValueKey('ReorderableSeparator${index}Key'),
            child: IgnorePointer(child: separator),
          );
        }

        return separator;
      }

      return itemBuilder.call(context, index ~/ 2);
    },
    onReorder: (int oldIndex, int newIndex) {
      if (oldIndex < newIndex) {
        newIndex -= 1;
      }

      if (oldIndex % 2 == 1) {
        //separator - should never happen
        return;
      }

      if ((oldIndex - newIndex).abs() == 1) {
        //moved behind the top/bottom separator
        return;
      }

      newIndex = oldIndex > newIndex && newIndex % 2 == 1
          ? (newIndex + 1) ~/ 2
          : newIndex ~/ 2;
      oldIndex = oldIndex ~/ 2;
      onReorder.call(oldIndex, newIndex);
    },
    itemExtent: itemExtent,
    prototypeItem: prototypeItem,
    proxyDecorator: proxyDecorator,
    buildDefaultDragHandles: buildDefaultDragHandles,
    padding: padding,
    header: header,
    scrollDirection: scrollDirection,
    reverse: reverse,
    scrollController: scrollController,
    primary: primary,
    physics: physics,
    shrinkWrap: shrinkWrap,
    anchor: anchor,
    cacheExtent: cacheExtent,
    dragStartBehavior: dragStartBehavior,
    keyboardDismissBehavior: keyboardDismissBehavior,
    restorationId: restorationId,
    clipBehavior: clipBehavior,
  );
}
    
                if ((oldIndex - newIndex).abs() == 1) {
                  return;
                }
    
                if (oldIndex > newIndex && newIndex % 2 == 1) {
                  newIndex = (newIndex + 1) ~/ 2;
                } else if (oldIndex > newIndex && newIndex % 2 != 1) {
                  newIndex = (newIndex) ~/ 2;
                } else if (newIndex == 0) {
                  newIndex = (newIndex ~/ 2);
                } else {
                  newIndex = (newIndex ~/ 2) + 1;
                }
                oldIndex = oldIndex ~/ 2;
                onReorder.call(oldIndex, newIndex);
              },
              itemExtent: itemExtent,
              prototypeItem: prototypeItem,
              proxyDecorator: proxyDecorator,
              buildDefaultDragHandles: buildDefaultDragHandles,
              padding: padding,
              header: header,
              scrollDirection: scrollDirection,
              reverse: reverse,
              scrollController: scrollController,
              primary: primary,
              physics: physics,
              shrinkWrap: shrinkWrap,
              anchor: anchor,
              cacheExtent: cacheExtent,
              dragStartBehavior: dragStartBehavior,
              keyboardDismissBehavior: keyboardDismissBehavior,
              restorationId: restorationId,
              clipBehavior: clipBehavior,
            );
    }

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