Created
August 13, 2024 09:19
-
-
Save sma/ae2faeabdeab65d91809106a119c8e16 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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