Browse Source

节点可拖动

master
hejl 3 weeks ago
parent
commit
4e377a67e9
  1. 91
      win_text_editor/lib/shared/components/tree_view.dart

91
win_text_editor/lib/shared/components/tree_view.dart

@ -23,6 +23,8 @@ class TreeViewConfig {
final Map<String, IconData> icons; final Map<String, IconData> icons;
final bool showRefreshButton; final bool showRefreshButton;
final IconData refreshIcon; final IconData refreshIcon;
final bool draggable; //
final bool droppable; //
const TreeViewConfig({ const TreeViewConfig({
this.lazyLoad = false, this.lazyLoad = false,
@ -34,6 +36,8 @@ class TreeViewConfig {
this.icons = const {}, this.icons = const {},
this.showRefreshButton = false, this.showRefreshButton = false,
this.refreshIcon = Icons.refresh, this.refreshIcon = Icons.refresh,
this.draggable = false,
this.droppable = false,
}); });
} }
@ -98,26 +102,75 @@ class _TreeViewState extends State<TreeView> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Stack( return Stack(
children: [ children: [
ListView.builder( DragTarget<TreeNode>(
controller: _effectiveController, onWillAcceptWithDetails: (data) {
physics: const ClampingScrollPhysics(), //
itemCount: _countVisibleNodes(widget.nodes), if (!widget.config.droppable) return false;
itemBuilder: (context, index) { return true;
final node = _getVisibleNode(widget.nodes, index); },
final isSelected = _selectedIds.contains(node.id); onAcceptWithDetails: (draggedNode) {
//
//
debugPrint('Dropped ${draggedNode.data.name}');
},
builder: (context, candidateData, rejectedData) {
return ListView.builder(
controller: _effectiveController,
physics: const ClampingScrollPhysics(),
itemCount: _countVisibleNodes(widget.nodes),
itemBuilder: (context, index) {
final node = _getVisibleNode(widget.nodes, index);
final isSelected = _selectedIds.contains(node.id);
return widget.nodeBuilder != null return widget.nodeBuilder != null
? widget.nodeBuilder!(context, node, isSelected, () => _handleNodeTap(node)) ? widget.nodeBuilder!(context, node, isSelected, () => _handleNodeTap(node))
: TreeNodeWidget( : Draggable<TreeNode>(
key: ValueKey(node.id), data: node,
node: node, feedback: Material(
config: widget.config, child: Container(
isSelected: isSelected, width: 200,
isChecked: _checkedIds.contains(node.id), padding: const EdgeInsets.all(8),
onTap: () => _handleNodeTap(node), decoration: BoxDecoration(
onDoubleTap: () => widget.onNodeDoubleTap?.call(node), color: Theme.of(context).cardColor,
onCheckChanged: (value) => _handleNodeCheckChanged(node, value), borderRadius: BorderRadius.circular(4),
); boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.2),
blurRadius: 4,
offset: const Offset(0, 2),
),
],
),
child: Text(node.title),
),
),
childWhenDragging: Opacity(
opacity: 0.5,
child: TreeNodeWidget(
key: ValueKey(node.id),
node: node,
config: widget.config,
isSelected: isSelected,
isChecked: _checkedIds.contains(node.id),
onTap: () => _handleNodeTap(node),
onDoubleTap: () => widget.onNodeDoubleTap?.call(node),
onCheckChanged: (value) => _handleNodeCheckChanged(node, value),
),
),
child: TreeNodeWidget(
key: ValueKey(node.id),
node: node,
config: widget.config,
isSelected: isSelected,
isChecked: _checkedIds.contains(node.id),
onTap: () => _handleNodeTap(node),
onDoubleTap: () => widget.onNodeDoubleTap?.call(node),
onCheckChanged: (value) => _handleNodeCheckChanged(node, value),
),
);
},
);
}, },
), ),

Loading…
Cancel
Save