将可重新排序的小部件(在 Wrap 中)与另一个容器中的小部件相结合,以实现多种拖放行为

问题描述 投票:0回答:1

我想在一行中有两个容器,每个容器都有自己的卡片小部件列表。

  1. 第一个(左侧)容器是一个卡片库,它是一个使卡片水平流动的包装。此包装中的卡片应该是可拖动/可放置的,以重新排列卡片的顺序,我正在查看这个库来解决这个问题。
  2. 第二个(右侧)容器应该是包含另一个卡片小部件列表的列。该容器本身也应该是可拖放的,以重新排列卡片的顺序。
  3. 除此之外,我希望能够将卡片从库(左侧容器)拖动到右侧容器,将卡片添加到右侧容器列表中正确的放置位置。
  4. 不应将卡片从左侧容器中移动/移除,它应仍保留在同一位置,但应在右侧容器中创建副本。
  5. 应该有某种指示符来指示从左到右容器(在其他卡之间)拖动时卡将添加到何处。

我认为将链接库与 Flutter DragTarget 相结合可能是一种可行的解决方案,但我不确定。

flutter drag-and-drop draggable
1个回答
0
投票
    import 'package:flutter/material.dart';


class DragDropExample extends StatefulWidget {
  @override
  _DragDropExampleState createState() => _DragDropExampleState();
}

class _DragDropExampleState extends State<DragDropExample> {
  List<String> libraryCards = ["Card A", "Card B", "Card C"];
  List<String> droppedCards = [];

  int? dropIndex; // To track where the card will be dropped

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Drag and Drop Example')),
      body: Row(
        children: [
          // Left Container: Library
          Expanded(
            flex: 1,
            child: Container(
              color: Colors.blue[50],
              padding: const EdgeInsets.all(8),
              child: Wrap(
                spacing: 8,
                runSpacing: 8,
                children: libraryCards.map((card) {
                  return Draggable<String>(
                    data: card,
                    feedback: Material(
                      child: Card(
                        color: Colors.blue[200],
                        child: Padding(
                          padding: const EdgeInsets.all(16),
                          child: Text(card),
                        ),
                      ),
                    ),
                    childWhenDragging: Opacity(
                      opacity: 0.5,
                      child: Card(
                        color: Colors.blue[100],
                        child: Padding(
                          padding: const EdgeInsets.all(16),
                          child: Text(card),
                        ),
                      ),
                    ),
                    child: Card(
                      color: Colors.blue[100],
                      child: Padding(
                        padding: const EdgeInsets.all(16),
                        child: Text(card),
                      ),
                    ),
                  );
                }).toList(),
              ),
            ),
          ),

          // Right Container: Droppable List
          Expanded(
            flex: 2,
            child: Container(
              color: Colors.green[50],
              padding: const EdgeInsets.all(8),
              child: DragTarget<String>(
                onAccept: (data) {
                  setState(() {
                    droppedCards.insert(dropIndex ?? droppedCards.length, data);
                    dropIndex = null; // Reset the drop index
                  });
                },
                onMove: (details) {
                  RenderBox renderBox = context.findRenderObject() as RenderBox;
                  double localDy = renderBox.globalToLocal(details.offset).dy;
                  double itemHeight = 70; // Approximate height of each card
                  dropIndex = (localDy / itemHeight).floor().clamp(0, droppedCards.length);
                  setState(() {});
                },
                onLeave: (_) => setState(() => dropIndex = null),
                builder: (context, candidateData, rejectedData) {
                  return Column(
                    children: [
                      for (int i = 0; i <= droppedCards.length; i++) ...[
                        if (i == dropIndex)
                          const Divider(
                            color: Colors.green,
                            thickness: 3,
                          ),
                        if (i < droppedCards.length)
                          Draggable<String>(
                            data: droppedCards[i],
                            feedback: Material(
                              child: Card(
                                color: Colors.green[200],
                                child: Padding(
                                  padding: const EdgeInsets.all(16),
                                  child: Text(droppedCards[i]),
                                ),
                              ),
                            ),
                            childWhenDragging: Opacity(
                              opacity: 0.5,
                              child: Card(
                                color: Colors.green[100],
                                child: Padding(
                                  padding: const EdgeInsets.all(16),
                                  child: Text(droppedCards[i]),
                                ),
                              ),
                            ),
                            onDragCompleted: () => droppedCards.removeAt(i),
                            child: Card(
                              color: Colors.green[100],
                              child: Padding(
                                padding: const EdgeInsets.all(16),
                                child: Text(droppedCards[i]),
                              ),
                            ),
                          ),
                      ],
                    ],
                  );
                },
              ),
            ),
          ),
        ],
      ),
    );
  }
}

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.