Closed devon closed 5 months ago
Hey @devon, thank you for using this package!
A drag handle approach should be doable already. You'd have to move the TreeDraggable
from around your tree tile down the widget tree to wrap your drag handle icon.
I intend to update the example app to be more mobile friendly (i.e., long press to drag or a drag handle as requested) when I get some spare time.
Hey @devon, thank you for using this package!
A drag handle approach should be doable already. You'd have to move the
TreeDraggable
from around your tree tile down the widget tree to wrap your drag handle icon.I intend to update the example app to be more mobile friendly (i.e., long press to drag or a drag handle as requested) when I get some spare time.
The mobile friendly example would be great. Thank you very much. I am starting to use this widget in a new app and it works very well. Love it.
For mobile drag-and-drop outlining (tree), the best app I have tried so far is Cloud Outliner. It supports dragging and dropping multiple items at once.
I am facing the same issue for scrolling and dragging. Any update on this?
Hey folks, sorry for taking so long to look into this. I just pushed a fix to the demo app which is now requiring a long press to start dragging on mobile platforms, this should fix the scrolling issue.
About the drag handle, I wrote a quick and unpolished version for demonstration purposes, I've tested it using the current DnD example from the demo app. It's currently a bit wonky on RTL directionality e.g., the feedback must be translated in TreeDraggable.dragAnchorStrategy
by the width of the TreeTile's content.
class DragAndDropTreeTile extends StatelessWidget {
const DragAndDropTreeTile({
super.key,
required this.entry,
this.onFolderPressed,
});
final TreeEntry<Node> entry;
final VoidCallback? onFolderPressed;
@override
Widget build(BuildContext context) {
final hoveredColor = Theme.of(context).colorScheme.primary.withOpacity(.3);
return TreeDragTarget(
node: entry.node,
onNodeAccepted: (TreeDragAndDropDetails details) {},
builder: (BuildContext context, TreeDragAndDropDetails? details) {
if (details != null) {
return ColoredBox(
color: hoveredColor,
child: TreeTile(
entry: entry,
),
);
}
return TreeTile(
entry: entry,
onFolderPressed: onFolderPressed,
);
},
);
}
}
class TreeTile extends StatefulWidget {
const TreeTile({
super.key,
required this.entry,
this.onFolderPressed,
this.isFeedback = false,
});
final TreeEntry<Node> entry;
final VoidCallback? onFolderPressed;
final bool isFeedback;
@override
State<TreeTile> createState() => _TreeTileState();
}
class _TreeTileState extends State<TreeTile> {
bool isDragging = false;
void onDragStarted() {
setState(() => isDragging = true);
}
void onDragEnd(DraggableDetails details) {
setState(() => isDragging = false);
}
@override
Widget build(BuildContext context) {
final Widget content = Opacity(
opacity: isDragging ? .5 : 1,
child: Padding(
padding: const EdgeInsetsDirectional.only(end: 8),
child: Row(
children: [
if (widget.isFeedback)
const Padding(
padding: EdgeInsetsDirectional.fromSTEB(8, 8, 0, 8),
child: Icon(Icons.drag_handle),
)
else
TreeDraggable(
node: widget.entry.node,
dragAnchorStrategy: childDragAnchorStrategy,
onDragStarted: onDragStarted,
onDragEnd: onDragEnd,
feedback: IntrinsicWidth(
child: Material(
elevation: 4,
child: TreeTile(
entry: widget.entry,
isFeedback: true,
),
),
),
child: const Padding(
padding: EdgeInsetsDirectional.fromSTEB(8, 8, 0, 8),
child: Icon(Icons.drag_handle),
),
),
FolderButton(
isOpen: widget.entry.isExpanded,
onPressed: widget.onFolderPressed,
),
Expanded(
child: Text('Node ${widget.entry.node.id}'),
),
],
),
),
);
if (widget.isFeedback) {
return content;
}
return TreeIndentation(
entry: widget.entry,
child: content,
);
}
}
It would be nice to add a drag handler to TreeDraggable. That way, we can easily scroll the tree and use the handler to drag nodes.