Skip to content

Instantly share code, notes, and snippets.

@sma
Created August 13, 2024 09:19
Show Gist options
  • Save sma/ae2faeabdeab65d91809106a119c8e16 to your computer and use it in GitHub Desktop.
Save sma/ae2faeabdeab65d91809106a119c8e16 to your computer and use it in GitHub Desktop.
import 'package:flutter/material.dart';
class RangeModel {
RangeModel(this.position, this.width);
final Offset position;
final double width;
}
class RangeView extends StatelessWidget {
const RangeView({
super.key,
required this.model,
this.onChanged,
this.onEnd,
this.child,
});
final RangeModel model;
final ValueChanged<RangeModel>? onChanged;
final VoidCallback? onEnd;
final Widget? child;
@override
Widget build(BuildContext context) {
return Positioned(
left: model.position.dx - 8,
top: model.position.dy,
width: model.width + 16,
height: 80,
child: GestureDetector(
onPanUpdate: (details) => onChanged?.call(
RangeModel(model.position + details.delta, model.width),
),
onPanEnd: (_) => onEnd?.call(),
child: Stack(
children: [
Positioned(
left: 8,
right: 8,
top: 0,
bottom: 0,
child: child ?? const SizedBox(),
),
Positioned(
left: 0,
width: 16,
top: 0,
bottom: 0,
child: MouseRegion(
cursor: SystemMouseCursors.resizeLeftRight,
child: GestureDetector(
onHorizontalDragUpdate: (details) => onChanged?.call(
RangeModel(
model.position + Offset(details.delta.dx, 0),
model.width - details.delta.dx,
),
),
onHorizontalDragEnd: (_) => onEnd?.call(),
),
),
),
Positioned(
right: 0,
width: 16,
top: 0,
bottom: 0,
child: MouseRegion(
cursor: SystemMouseCursors.resizeLeftRight,
child: GestureDetector(
onHorizontalDragUpdate: (details) => onChanged?.call(
RangeModel(model.position, model.width + details.delta.dx),
),
onHorizontalDragEnd: (_) => onEnd?.call(),
),
),
),
],
),
),
);
}
}
class RangeContainer extends StatefulWidget {
const RangeContainer({super.key});
@override
State<RangeContainer> createState() => _RangeContainerState();
}
class _RangeContainerState extends State<RangeContainer> {
RangeModel _model = RangeModel(Offset.zero, 128);
@override
Widget build(BuildContext context) {
return Stack(
children: [
RangeView(
model: _model,
onChanged: (model) => setState(() => _model = model),
onEnd: _snapToGrid,
child: Container(
color: Colors.amber,
alignment: Alignment.center,
child: const Text('Drag me'),
),
),
],
);
}
void _snapToGrid() {
setState(() {
_model = RangeModel(
Offset(
_model.position.dx.snapTo(8),
_model.position.dy.snapTo(64),
),
_model.width.snapTo(48),
);
});
}
}
extension on double {
double snapTo(double d) => (this / d).roundToDouble() * d;
}
void main() {
runApp(
MaterialApp(
debugShowMaterialGrid: false,
home: Scaffold(
body: RangeContainer(),
),
),
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment