Skip to content

Commit add9c61

Browse files
authored
feat: custom ReorderableListView drag handle listeners (#5051)
* initial commit * `ReorderableListView`: mouse_cursor, show_default_drag_handles * generated files * flutter 3.29.0
1 parent 440009d commit add9c61

File tree

7 files changed

+211
-2
lines changed

7 files changed

+211
-2
lines changed

packages/flet/lib/src/controls/create_control.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ import 'progress_ring.dart';
9393
import 'radio.dart';
9494
import 'radio_group.dart';
9595
import 'range_slider.dart';
96+
import 'reorderable_draggable.dart';
9697
import 'reorderable_list_view.dart';
9798
import 'responsive_row.dart';
9899
import 'row.dart';
@@ -716,6 +717,15 @@ Widget createWidget(
716717
parentDisabled: parentDisabled,
717718
parentAdaptive: parentAdaptive,
718719
backend: backend);
720+
case "reorderabledraggable":
721+
return ReorderableDraggableControl(
722+
key: key,
723+
parent: parent,
724+
control: controlView.control,
725+
children: controlView.children,
726+
parentDisabled: parentDisabled,
727+
parentAdaptive: parentAdaptive,
728+
);
719729
case "gridview":
720730
return GridViewControl(
721731
key: key,
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import 'package:flutter/material.dart';
2+
3+
import '../models/control.dart';
4+
import 'create_control.dart';
5+
import 'error.dart';
6+
7+
class ReorderableDraggableControl extends StatefulWidget {
8+
final Control? parent;
9+
final Control control;
10+
final bool parentDisabled;
11+
final List<Control> children;
12+
final bool? parentAdaptive;
13+
14+
const ReorderableDraggableControl(
15+
{super.key,
16+
this.parent,
17+
required this.control,
18+
required this.children,
19+
required this.parentDisabled,
20+
required this.parentAdaptive});
21+
22+
@override
23+
State<ReorderableDraggableControl> createState() => _ListViewControlState();
24+
}
25+
26+
class _ListViewControlState extends State<ReorderableDraggableControl> {
27+
@override
28+
Widget build(BuildContext context) {
29+
debugPrint("ReorderableDraggableControl build: ${widget.control.id}");
30+
31+
bool? adaptive =
32+
widget.control.attrBool("adaptive") ?? widget.parentAdaptive;
33+
34+
var index = widget.control.attrInt("index");
35+
if (index == null) {
36+
return const ErrorControl("ReorderableDraggable.index is invalid");
37+
}
38+
var content = widget.children.where((c) => c.isVisible).firstOrNull;
39+
if (content == null) {
40+
return const ErrorControl(
41+
"ReorderableDraggable.content must be set and visible");
42+
}
43+
44+
return ReorderableDragStartListener(
45+
index: index,
46+
child: createControl(widget.control, content.id, widget.parentDisabled,
47+
parentAdaptive: adaptive));
48+
}
49+
}

packages/flet/lib/src/controls/reorderable_list_view.dart

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class _ListViewControlState extends State<ReorderableListViewControl> {
4949

5050
@override
5151
Widget build(BuildContext context) {
52-
debugPrint("ListViewControl build: ${widget.control.id}");
52+
debugPrint("ReorderableDraggableControl build: ${widget.control.id}");
5353

5454
bool disabled = widget.control.isDisabled || widget.parentDisabled;
5555
bool? adaptive =
@@ -64,7 +64,11 @@ class _ListViewControlState extends State<ReorderableListViewControl> {
6464
widget.control.attrBool("firstItemPrototype", false)!;
6565
var padding = parseEdgeInsets(widget.control, "padding");
6666
var reverse = widget.control.attrBool("reverse", false)!;
67+
var showDefaultDragHandles =
68+
widget.control.attrBool("showDefaultDragHandles", true)!;
6769
var anchor = widget.control.attrDouble("anchor", 0.0)!;
70+
var mouseCursor =
71+
parseMouseCursor(widget.control.attrString("mouseCursor"));
6872
var clipBehavior =
6973
parseClip(widget.control.attrString("clipBehavior"), Clip.hardEdge)!;
7074
List<Control> ctrls = widget.children
@@ -126,11 +130,13 @@ class _ListViewControlState extends State<ReorderableListViewControl> {
126130
clipBehavior: clipBehavior,
127131
reverse: reverse,
128132
cacheExtent: cacheExtent,
133+
buildDefaultDragHandles: showDefaultDragHandles,
129134
scrollDirection: scrollDirection,
130135
shrinkWrap: shrinkWrap,
131136
padding: padding,
132137
itemCount: ctrls.length,
133138
itemExtent: itemExtent,
139+
mouseCursor: mouseCursor,
134140
anchor: anchor,
135141
header: header,
136142
footer: footer,
@@ -151,13 +157,15 @@ class _ListViewControlState extends State<ReorderableListViewControl> {
151157
cacheExtent: cacheExtent,
152158
reverse: reverse,
153159
clipBehavior: clipBehavior,
160+
buildDefaultDragHandles: showDefaultDragHandles,
154161
scrollDirection: scrollDirection,
155162
shrinkWrap: shrinkWrap,
156163
padding: padding,
157164
anchor: anchor,
158165
header: header,
159166
footer: footer,
160167
itemExtent: itemExtent,
168+
mouseCursor: mouseCursor,
161169
prototypeItem: prototypeItem,
162170
autoScrollerVelocityScalar: autoScrollerVelocityScalar,
163171
mouseCursor: mouseCursor,

sdk/python/packages/flet-cli/src/flet_cli/commands/build.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import re
66
import shutil
77
import sys
8-
import time
98
from pathlib import Path
109
from typing import Optional, cast
1110

sdk/python/packages/flet/src/flet/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from flet.core.animated_switcher import AnimatedSwitcher, AnimatedSwitcherTransition
66
from flet.core.animation import Animation, AnimationCurve
77
from flet.core.app_bar import AppBar
8+
from flet.core.reorderable_draggable import ReorderableDraggable
89
from flet.core.audio import (
910
Audio,
1011
AudioDurationChangeEvent,
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
from typing import Any, Optional, Union
2+
3+
from flet.core.adaptive_control import AdaptiveControl
4+
from flet.core.animation import AnimationValue
5+
from flet.core.badge import BadgeValue
6+
from flet.core.constrained_control import ConstrainedControl
7+
from flet.core.control import Control, OptionalNumber
8+
from flet.core.ref import Ref
9+
from flet.core.tooltip import TooltipValue
10+
from flet.core.types import (
11+
OffsetValue,
12+
OptionalControlEventCallable,
13+
PaddingValue,
14+
ResponsiveNumber,
15+
RotateValue,
16+
ScaleValue,
17+
)
18+
19+
20+
class ReorderableDraggable(ConstrainedControl, AdaptiveControl):
21+
def __init__(
22+
self,
23+
index: int,
24+
content: Control,
25+
#
26+
# ConstrainedControl
27+
#
28+
ref: Optional[Ref] = None,
29+
key: Optional[str] = None,
30+
width: OptionalNumber = None,
31+
height: OptionalNumber = None,
32+
expand: Union[None, bool, int] = None,
33+
expand_loose: Optional[bool] = None,
34+
col: Optional[ResponsiveNumber] = None,
35+
opacity: OptionalNumber = None,
36+
rotate: Optional[RotateValue] = None,
37+
scale: Optional[ScaleValue] = None,
38+
offset: Optional[OffsetValue] = None,
39+
aspect_ratio: OptionalNumber = None,
40+
animate_opacity: Optional[AnimationValue] = None,
41+
animate_size: Optional[AnimationValue] = None,
42+
animate_position: Optional[AnimationValue] = None,
43+
animate_rotation: Optional[AnimationValue] = None,
44+
animate_scale: Optional[AnimationValue] = None,
45+
animate_offset: Optional[AnimationValue] = None,
46+
on_animation_end: OptionalControlEventCallable = None,
47+
tooltip: Optional[TooltipValue] = None,
48+
visible: Optional[bool] = None,
49+
disabled: Optional[bool] = None,
50+
data: Any = None,
51+
rtl: Optional[bool] = None,
52+
#
53+
# Adaptive
54+
#
55+
adaptive: Optional[bool] = None,
56+
):
57+
ConstrainedControl.__init__(
58+
self,
59+
ref=ref,
60+
key=key,
61+
width=width,
62+
height=height,
63+
expand=expand,
64+
expand_loose=expand_loose,
65+
col=col,
66+
opacity=opacity,
67+
rotate=rotate,
68+
scale=scale,
69+
offset=offset,
70+
aspect_ratio=aspect_ratio,
71+
animate_opacity=animate_opacity,
72+
animate_size=animate_size,
73+
animate_position=animate_position,
74+
animate_rotation=animate_rotation,
75+
animate_scale=animate_scale,
76+
animate_offset=animate_offset,
77+
on_animation_end=on_animation_end,
78+
tooltip=tooltip,
79+
visible=visible,
80+
disabled=disabled,
81+
data=data,
82+
rtl=rtl,
83+
)
84+
85+
AdaptiveControl.__init__(self, adaptive=adaptive)
86+
87+
self.content = content
88+
self.index = index
89+
90+
def _get_control_name(self):
91+
return "reorderabledraggable"
92+
93+
def before_update(self):
94+
super().before_update()
95+
assert self.__content.visible, "content must be visible"
96+
97+
def _get_children(self):
98+
self.__content._set_attr_internal("n", "content")
99+
return [self.__content]
100+
101+
# index
102+
@property
103+
def index(self) -> int:
104+
return self._get_attr("index", data_type="int")
105+
106+
@index.setter
107+
def index(self, value: int):
108+
self._set_attr("index", value)
109+
110+
# content
111+
@property
112+
def content(self) -> Control:
113+
return self.__content
114+
115+
@content.setter
116+
def content(self, value: Control):
117+
self.__content = value

sdk/python/packages/flet/src/flet/core/reorderable_list_view.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
ResponsiveNumber,
1919
RotateValue,
2020
ScaleValue,
21+
MouseCursor,
2122
)
2223

2324

@@ -52,6 +53,7 @@ def __init__(
5253
header: Optional[Control] = None,
5354
footer: Optional[Control] = None,
5455
build_controls_on_demand: Optional[bool] = None,
56+
show_default_drag_handles: Optional[bool] = None,
5557
mouse_cursor: Optional[MouseCursor] = None,
5658
on_reorder: OptionalEventCallable[OnReorderEvent] = None,
5759
on_reorder_start: OptionalEventCallable[OnReorderEvent] = None,
@@ -147,6 +149,8 @@ def __init__(
147149
self.on_reorder = on_reorder
148150
self.anchor = anchor
149151
self.auto_scroller_velocity_scalar = auto_scroller_velocity_scalar
152+
self.show_default_drag_handles = show_default_drag_handles
153+
self.mouse_cursor = mouse_cursor
150154
self.on_reorder_start = on_reorder_start
151155
self.on_reorder_end = on_reorder_end
152156
self.mouse_cursor = mouse_cursor
@@ -213,6 +217,27 @@ def footer(self) -> Optional[Control]:
213217
def footer(self, value: Optional[Control]):
214218
self.__footer = value
215219

220+
# show_default_drag_handles
221+
@property
222+
def show_default_drag_handles(self) -> Optional[bool]:
223+
return self._get_attr(
224+
"showDefaultDragHandles", data_type="bool", def_value=True
225+
)
226+
227+
@show_default_drag_handles.setter
228+
def show_default_drag_handles(self, value: Optional[bool]):
229+
self._set_attr("showDefaultDragHandles", value)
230+
231+
# mouse_cursor
232+
@property
233+
def mouse_cursor(self) -> Optional[MouseCursor]:
234+
return self.__mouse_cursor
235+
236+
@mouse_cursor.setter
237+
def mouse_cursor(self, value: Optional[MouseCursor]):
238+
self.__mouse_cursor = value
239+
self._set_enum_attr("mouseCursor", value, MouseCursor)
240+
216241
# on_reorder
217242
@property
218243
def on_reorder(self) -> OptionalEventCallable[OnReorderEvent]:

0 commit comments

Comments
 (0)