Skip to content

Instantly share code, notes, and snippets.

@nhancv
Created January 14, 2021 17:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nhancv/7e3254ac67754b115657e4f0880f8277 to your computer and use it in GitHub Desktop.
Save nhancv/7e3254ac67754b115657e4f0880f8277 to your computer and use it in GitHub Desktop.
Flutter draggable widget
/// Draggable widget
class _WDraggable extends StatefulWidget {
const _WDraggable({Key key, this.child, this.valueChanged}) : super(key: key);
final Widget child;
final ValueChanged<Offset> valueChanged;
@override
_WDraggableState createState() => _WDraggableState();
}
class _WDraggableState extends State<_WDraggable> {
ValueNotifier<Offset> valueListener = ValueNotifier<Offset>(const Offset(1, 1));
@override
void initState() {
valueListener.addListener(_notifyParent);
super.initState();
}
@override
Widget build(BuildContext context) {
return Builder(
builder: (BuildContext context) {
final GestureDetector handle = GestureDetector(
onPanUpdate: (DragUpdateDetails details) {
final double dx = (valueListener.value.dx +
(details.delta.dx / context.size.width))
.clamp(0.0, 1.0)
.toDouble();
final double dy = (valueListener.value.dy -
(details.delta.dy / context.size.height))
.clamp(0.0, 1.0)
.toDouble();
valueListener.value = Offset(dx, dy);
},
child: widget.child,
);
return AnimatedBuilder(
animation: valueListener,
builder: (_, Widget child) {
return Align(
alignment: Alignment(valueListener.value.dx * 2 - 1,
1 - valueListener.value.dy * 2),
child: child,
);
},
child: handle,
);
},
);
}
// Notify change to parent
void _notifyParent() {
if (widget.valueChanged != null) {
widget.valueChanged(valueListener.value);
}
}
}
import 'package:flutter/material.dart';
/// Draggable widget Horizontal only, constraining with parent size
class WDraggableH extends StatefulWidget {
const WDraggableH(this.child, {Key key, this.valueChanged}) : super(key: key);
final Widget child;
final ValueChanged<double> valueChanged;
@override
_WDraggableHState createState() => _WDraggableHState();
}
class _WDraggableHState extends State<WDraggableH> {
ValueNotifier<double> valueListener = ValueNotifier<double>(0);
@override
void initState() {
valueListener.addListener(_notifyParent);
super.initState();
}
@override
Widget build(BuildContext context) {
return Builder(
builder: (BuildContext context) {
final GestureDetector handle = GestureDetector(
onHorizontalDragUpdate: (DragUpdateDetails details) {
valueListener.value =
(valueListener.value + (details.delta.dx / context.size.width))
.clamp(0.0, 1.0)
.toDouble();
},
child: widget.child,
);
return AnimatedBuilder(
animation: valueListener,
builder: (_, Widget child) {
return Align(
alignment: Alignment(valueListener.value * 2 - 1, 0),
child: child,
);
},
child: handle,
);
},
);
}
// Notify change to parent
void _notifyParent() {
if (widget.valueChanged != null) {
widget.valueChanged(valueListener.value);
}
}
}
import 'package:flutter/material.dart';
/// Draggable widget Vertical only, constraining with parent size
class WDraggableV extends StatefulWidget {
const WDraggableV({Key key, this.child, this.valueChanged}) : super(key: key);
final Widget child;
final ValueChanged<double> valueChanged;
@override
_WDraggableVState createState() => _WDraggableVState();
}
class _WDraggableVState extends State<WDraggableV> {
ValueNotifier<double> valueListener = ValueNotifier<double>(0);
@override
void initState() {
valueListener.addListener(_notifyParent);
super.initState();
}
@override
Widget build(BuildContext context) {
return Builder(
builder: (BuildContext context) {
final GestureDetector handle = GestureDetector(
onVerticalDragUpdate: (DragUpdateDetails details) {
valueListener.value =
(valueListener.value - (details.delta.dy / context.size.height))
.clamp(0.0, 1.0)
.toDouble();
},
child: widget.child,
);
return AnimatedBuilder(
animation: valueListener,
builder: (_, Widget child) {
return Align(
alignment: Alignment(0, 1 - valueListener.value * 2),
child: child,
);
},
child: handle,
);
},
);
}
// Notify change to parent
void _notifyParent() {
if (widget.valueChanged != null) {
widget.valueChanged(valueListener.value);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment