@@ -49,115 +49,155 @@ class OneAxisJoystick extends StatefulWidget {
4949}
5050
5151class _OneAxisJoystickState extends State <OneAxisJoystick > {
52+ final thumbKey = GlobalKey ();
53+
54+ void onPanUpdate (DragUpdateDetails details) {
55+ final delta = widget.axis.isVertical ? - details.delta.dy : details.delta.dx;
56+ widget.controller.onDragUpdate (delta);
57+ widget.notifier.updateCurrentPosition (delta);
58+ }
59+
60+ void onCancel ([Axis ? axis]) {
61+ if (axis != null && axis != widget.axis) return ;
62+ widget.controller.onDragEnd ();
63+ widget.notifier.moveAnimated ();
64+ }
65+
66+ void onStart ([Axis ? axis]) {
67+ if (axis != null && axis != widget.axis) return ;
68+ widget.controller.onDragStart ();
69+ }
70+
5271 @override
5372 Widget build (BuildContext context) {
5473 final axis = widget.axis;
5574 final isVertical = axis.isVertical;
5675
57- return SizedBox (
58- height: isVertical ? widget.mainAxisSize : null ,
59- width: isVertical ? widget.crossAxisSize : widget.mainAxisSize,
60- child: LayoutBuilder (
61- builder: (context, constraints) {
62- widget.notifier.setMaxDistance (widget.mainAxisSize);
63- return ValueListenableBuilder <OneAxisValue >(
64- valueListenable: widget.notifier,
65- builder: (context, value, child) {
66- final factor = value.factor;
67- final xAlignment = isVertical ? 0.0 : factor;
68- final yAlignment = isVertical ? factor : 0.0 ;
69- return Stack (
70- alignment: Alignment (xAlignment, - yAlignment),
71- children: [
72- Positioned .fill (
73- top: isVertical ? widget.arrowIconPadding : 0 ,
74- right: isVertical ? 0 : null ,
75- bottom: isVertical ? null : 0 ,
76- child: Center (
77- child: Icon (
78- isVertical
79- ? Icons .keyboard_arrow_up_rounded
80- : Icons .keyboard_arrow_left_rounded,
81- size: widget.iconSize,
82- color: context.colors.disabled,
76+ return GestureDetector (
77+ onPanDown: (details) {
78+ final tapOffset = details.globalPosition;
79+ final renderBox =
80+ thumbKey.currentContext? .findRenderObject () as RenderBox ? ;
81+
82+ if (renderBox == null ) return ;
83+ final size = renderBox.size;
84+
85+ final buttonTopRightOffset = renderBox.localToGlobal (Offset .zero);
86+ final buttonCenter =
87+ buttonTopRightOffset + Offset (size.width / 2 , size.height / 2 );
88+
89+ final buttonRect = Rect .fromCenter (
90+ center: buttonCenter,
91+ width: widget.thumbSize,
92+ height: widget.thumbSize,
93+ );
94+
95+ final isTapOnButton = buttonRect.contains (tapOffset);
96+
97+ if (isTapOnButton) return ;
98+ final offsetDelta = tapOffset - buttonCenter;
99+ final delta = isVertical ? - offsetDelta.dy : offsetDelta.dx;
100+ widget.notifier.updateCurrentPosition (delta);
101+ },
102+ onTapUp: (_) => onCancel (),
103+ onPanStart: (_) => onStart (),
104+ onPanUpdate: onPanUpdate,
105+ onLongPressStart: (_) => onStart (),
106+ onLongPressMoveUpdate: (details) {
107+ final currentPosition = widget.axis.isVertical
108+ ? widget.mainAxisSize - widget.notifier.value.currentPosition
109+ : widget.notifier.value.currentPosition;
110+ final delta = widget.axis.isVertical
111+ ? currentPosition - details.localPosition.dy
112+ : details.localPosition.dx - currentPosition;
113+ widget.controller.onDragUpdate (delta);
114+ widget.notifier.updateCurrentPosition (delta);
115+ },
116+ onPanEnd: (_) => onCancel (),
117+ onLongPressEnd: (_) => onCancel (),
118+ child: ColoredBox (
119+ color: Colors .transparent,
120+ child: SizedBox (
121+ height: isVertical ? widget.mainAxisSize : null ,
122+ width: isVertical ? widget.crossAxisSize : widget.mainAxisSize,
123+ child: LayoutBuilder (
124+ builder: (context, constraints) {
125+ widget.notifier.setMaxDistance (widget.mainAxisSize);
126+ return ValueListenableBuilder <OneAxisValue >(
127+ valueListenable: widget.notifier,
128+ builder: (context, value, child) {
129+ final factor = value.factor;
130+ final xAlignment = isVertical ? 0.0 : factor;
131+ final yAlignment = isVertical ? factor : 0.0 ;
132+ return Stack (
133+ alignment: Alignment (xAlignment, - yAlignment),
134+ children: [
135+ Positioned .fill (
136+ top: isVertical ? widget.arrowIconPadding : 0 ,
137+ right: isVertical ? 0 : null ,
138+ bottom: isVertical ? null : 0 ,
139+ child: Center (
140+ child: Icon (
141+ isVertical
142+ ? Icons .keyboard_arrow_up_rounded
143+ : Icons .keyboard_arrow_left_rounded,
144+ size: widget.iconSize,
145+ color: context.colors.disabled,
146+ ),
147+ ),
83148 ),
84- ),
85- ),
86- Positioned .fill (
87- bottom: isVertical ? widget.arrowIconPadding : 0 ,
88- left: isVertical ? 0 : null ,
89- top: isVertical ? null : 0 ,
90- child: Center (
91- child: Icon (
92- isVertical
93- ? Icons .keyboard_arrow_down_rounded
94- : Icons .keyboard_arrow_right_rounded,
95- size: widget.iconSize,
96- color: context.colors.disabled,
149+ Positioned .fill (
150+ bottom: isVertical ? widget.arrowIconPadding : 0 ,
151+ left: isVertical ? 0 : null ,
152+ top: isVertical ? null : 0 ,
153+ child: Center (
154+ child: Icon (
155+ isVertical
156+ ? Icons .keyboard_arrow_down_rounded
157+ : Icons .keyboard_arrow_right_rounded,
158+ size: widget.iconSize,
159+ color: context.colors.disabled,
160+ ),
161+ ),
162+ ),
163+ child ?? const SizedBox .shrink (),
164+ ],
165+ );
166+ },
167+ child: GestureDetector (
168+ key: thumbKey,
169+ onVerticalDragStart: (_) => onStart (Axis .vertical),
170+ onVerticalDragUpdate: onPanUpdate,
171+ onVerticalDragEnd: (_) => onCancel (Axis .vertical),
172+ onHorizontalDragStart: (_) => onStart (Axis .horizontal),
173+ onHorizontalDragUpdate: onPanUpdate,
174+ onHorizontalDragEnd: (_) => onCancel (Axis .horizontal),
175+ onTap: widget.controller.onTap,
176+ child: SizedBox .square (
177+ dimension: widget.thumbSize,
178+ child: ColoredBox (
179+ color: Colors .transparent,
180+ child: DecoratedBox (
181+ decoration: BoxDecoration (
182+ shape: BoxShape .circle,
183+ color: context.colors.disabled,
184+ border: Border .all (color: Colors .black26),
185+ boxShadow: const [
186+ BoxShadow (
187+ color: Colors .black12,
188+ blurRadius: 3 ,
189+ spreadRadius: 3 ,
190+ ),
191+ ],
192+ ),
97193 ),
98194 ),
99195 ),
100- child ?? const SizedBox .shrink (),
101- ],
196+ ),
102197 );
103198 },
104- child: GestureDetector (
105- onVerticalDragStart: ! isVertical
106- ? null
107- : (details) {
108- widget.controller.onDragStart ();
109- },
110- onVerticalDragUpdate: ! isVertical
111- ? null
112- : (details) {
113- widget.notifier.updateCurrentPosition (- details.delta.dy);
114- },
115- onVerticalDragEnd: ! isVertical
116- ? null
117- : (details) {
118- widget.controller.onDragEnd ();
119- widget.notifier.moveAnimated ();
120- },
121- onHorizontalDragStart: isVertical
122- ? null
123- : (details) {
124- widget.controller.onDragStart ();
125- },
126- onHorizontalDragUpdate: isVertical
127- ? null
128- : (details) {
129- final delta =
130- isVertical ? details.delta.dy : details.delta.dx;
131- widget.controller.onDragUpdate (delta);
132- widget.notifier.updateCurrentPosition (delta);
133- },
134- onHorizontalDragEnd: isVertical
135- ? null
136- : (details) {
137- widget.controller.onDragEnd ();
138- widget.notifier.moveAnimated ();
139- },
140- onTap: widget.controller.onTap,
141- child: SizedBox .square (
142- dimension: widget.thumbSize,
143- child: DecoratedBox (
144- decoration: BoxDecoration (
145- shape: BoxShape .circle,
146- color: context.colors.disabled,
147- border: Border .all (color: Colors .black26),
148- boxShadow: const [
149- BoxShadow (
150- color: Colors .black12,
151- blurRadius: 3 ,
152- spreadRadius: 3 ,
153- ),
154- ],
155- ),
156- ),
157- ),
158- ),
159- );
160- },
199+ ),
200+ ),
161201 ),
162202 );
163203 }
0 commit comments