mirror of
https://github.com/Iconica-Development/flutter_date_time_picker.git
synced 2025-05-18 18:33:49 +02:00
Merge pull request #18 from Iconica-Development/feature/dismissable-pop-up
Made the popup dismissable
This commit is contained in:
commit
ca78fb2a4c
5 changed files with 127 additions and 64 deletions
|
@ -1,4 +1,9 @@
|
||||||
|
## 2.2.2
|
||||||
|
|
||||||
|
- Made the popup dismissible
|
||||||
|
|
||||||
## 2.2.1
|
## 2.2.1
|
||||||
|
|
||||||
- Added marking to datetimepicker
|
- Added marking to datetimepicker
|
||||||
|
|
||||||
## 2.2.0
|
## 2.2.0
|
||||||
|
|
|
@ -10,7 +10,7 @@ A picker that is placed in the top of the screen.
|
||||||
You are able to select a day for a given week.
|
You are able to select a day for a given week.
|
||||||
When it is dragged down you are able to select a day for a given month.
|
When it is dragged down you are able to select a day for a given month.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
### OverlayDateTimePicker
|
### OverlayDateTimePicker
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ packages:
|
||||||
path: ".."
|
path: ".."
|
||||||
relative: true
|
relative: true
|
||||||
source: path
|
source: path
|
||||||
version: "2.2.0"
|
version: "2.2.2"
|
||||||
flutter_lints:
|
flutter_lints:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -102,29 +102,8 @@ class _OverlayDateTimePickerState extends State<OverlayDateTimePicker> {
|
||||||
|
|
||||||
bool _isShown = false;
|
bool _isShown = false;
|
||||||
|
|
||||||
late OverlayState? _overlayState;
|
_DropdownRoute? _dropdownRoute;
|
||||||
|
|
||||||
late final OverlayEntry _overlay = OverlayEntry(
|
|
||||||
builder: (context) {
|
|
||||||
var box = buttonKey.currentContext?.findRenderObject() as RenderBox;
|
|
||||||
var offset = _calculateOffset(
|
|
||||||
alignment: widget.alignment,
|
|
||||||
position: box.localToGlobal(
|
|
||||||
const Offset(0, 0),
|
|
||||||
),
|
|
||||||
buttonSize: box.size,
|
|
||||||
overlaySize: widget.size,
|
|
||||||
);
|
|
||||||
return Positioned(
|
|
||||||
top: offset.dy,
|
|
||||||
left: offset.dx,
|
|
||||||
child: Material(
|
|
||||||
color: Colors.transparent,
|
|
||||||
child: _buildOverlay(context),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
late final DateTimePickerController _dateTimePickerController =
|
late final DateTimePickerController _dateTimePickerController =
|
||||||
DateTimePickerController(
|
DateTimePickerController(
|
||||||
highlightToday: widget.highlightToday,
|
highlightToday: widget.highlightToday,
|
||||||
|
@ -137,7 +116,7 @@ class _OverlayDateTimePickerState extends State<OverlayDateTimePicker> {
|
||||||
onTapDayCallBack: (date) {
|
onTapDayCallBack: (date) {
|
||||||
widget.onTapDay?.call(date);
|
widget.onTapDay?.call(date);
|
||||||
if (widget.closeOnSelectDate) {
|
if (widget.closeOnSelectDate) {
|
||||||
_toggleOverlay();
|
Navigator.of(context).pop();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
browsingDate: widget.initialDate ?? DateTime.now(),
|
browsingDate: widget.initialDate ?? DateTime.now(),
|
||||||
|
@ -146,65 +125,61 @@ class _OverlayDateTimePickerState extends State<OverlayDateTimePicker> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
if (_overlay.mounted) _overlay.remove();
|
|
||||||
_overlay.dispose();
|
|
||||||
_overlayState = null;
|
|
||||||
_dateTimePickerController.dispose();
|
_dateTimePickerController.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _toggleOverlay() {
|
void _onPressed() async {
|
||||||
if (mounted && (_overlayState?.mounted ?? false)) {
|
if (!mounted) return;
|
||||||
setState(() {
|
setState(() {
|
||||||
if (!_isShown) {
|
_isShown = !_isShown;
|
||||||
_overlayState?.insert(_overlay);
|
});
|
||||||
} else {
|
final TextDirection? textDirection = Directionality.maybeOf(context);
|
||||||
_overlay.remove();
|
|
||||||
}
|
final NavigatorState navigator = Navigator.of(context);
|
||||||
_isShown = !_isShown;
|
|
||||||
});
|
final RenderBox buttonBox = context.findRenderObject()! as RenderBox;
|
||||||
|
final Rect buttonRect = buttonBox.localToGlobal(Offset.zero,
|
||||||
|
ancestor: navigator.context.findRenderObject()) &
|
||||||
|
buttonBox.size;
|
||||||
|
|
||||||
|
_dropdownRoute = _DropdownRoute(
|
||||||
|
child: _buildOverlay(context),
|
||||||
|
barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
|
||||||
|
buttonRect:
|
||||||
|
EdgeInsets.zero.resolve(textDirection).inflateRect(buttonRect),
|
||||||
|
alignment: widget.alignment,
|
||||||
|
menuSize: widget.size,
|
||||||
|
);
|
||||||
|
await navigator.push(_dropdownRoute!);
|
||||||
|
if (!mounted) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_close();
|
||||||
}
|
}
|
||||||
|
|
||||||
Offset _calculateOffset({
|
void _close() {
|
||||||
required Alignment alignment,
|
if (!mounted) return;
|
||||||
required Offset position,
|
setState(() {
|
||||||
required Size buttonSize,
|
_isShown = false;
|
||||||
required Size overlaySize,
|
});
|
||||||
}) {
|
|
||||||
double offsetX = 0;
|
|
||||||
double offsetY = 0;
|
|
||||||
|
|
||||||
offsetX = position.dx + // adds the world x position of the button
|
|
||||||
buttonSize.width *
|
|
||||||
0.5 - // centers the pivot of the button of the calculation to the center of the button
|
|
||||||
overlaySize.width *
|
|
||||||
0.5 + // centers the pivot of the overlay of the calculation to the center of the overlay
|
|
||||||
(overlaySize.width + buttonSize.width) * 0.5 * alignment.x;
|
|
||||||
offsetY = position.dy + // adds the world y position of the button
|
|
||||||
buttonSize.height * 0.5 -
|
|
||||||
overlaySize.height * 0.5 +
|
|
||||||
(overlaySize.height + buttonSize.height) * 0.5 * alignment.y;
|
|
||||||
|
|
||||||
return Offset(offsetX, offsetY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
_overlayState = Overlay.of(context);
|
|
||||||
|
|
||||||
if (widget.buttonBuilder != null) {
|
if (widget.buttonBuilder != null) {
|
||||||
return widget.buttonBuilder!.call(
|
return widget.buttonBuilder!.call(
|
||||||
buttonKey,
|
buttonKey,
|
||||||
() {
|
() {
|
||||||
_toggleOverlay();
|
_onPressed();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return ElevatedButton(
|
return ElevatedButton(
|
||||||
key: buttonKey,
|
key: buttonKey,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
_toggleOverlay();
|
_onPressed();
|
||||||
},
|
},
|
||||||
child: widget.child);
|
child: widget.child);
|
||||||
}
|
}
|
||||||
|
@ -284,3 +259,86 @@ class _OverlayDateTimePickerState extends State<OverlayDateTimePicker> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _DropdownRoute extends PopupRoute<Widget> {
|
||||||
|
_DropdownRoute({
|
||||||
|
required this.barrierLabel,
|
||||||
|
required this.child,
|
||||||
|
required this.alignment,
|
||||||
|
required this.menuSize,
|
||||||
|
required this.buttonRect,
|
||||||
|
});
|
||||||
|
|
||||||
|
final Widget child;
|
||||||
|
final Alignment alignment;
|
||||||
|
final Size menuSize;
|
||||||
|
final Rect buttonRect;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get barrierColor => null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get barrierDismissible => true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
final String? barrierLabel;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget buildPage(BuildContext context, Animation<double> animation,
|
||||||
|
Animation<double> secondaryAnimation) {
|
||||||
|
return CustomSingleChildLayout(
|
||||||
|
delegate: _DropdownMenuLayoutDelegate(
|
||||||
|
buttonRect: buttonRect,
|
||||||
|
menuSize: menuSize,
|
||||||
|
alignment: alignment,
|
||||||
|
),
|
||||||
|
child: Material(child: child),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Duration get transitionDuration => const Duration(milliseconds: 100);
|
||||||
|
|
||||||
|
void dismiss() {
|
||||||
|
navigator?.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DropdownMenuLayoutDelegate extends SingleChildLayoutDelegate {
|
||||||
|
_DropdownMenuLayoutDelegate({
|
||||||
|
required this.buttonRect,
|
||||||
|
required this.menuSize,
|
||||||
|
required this.alignment,
|
||||||
|
});
|
||||||
|
|
||||||
|
final Rect buttonRect;
|
||||||
|
final Size menuSize;
|
||||||
|
final Alignment alignment;
|
||||||
|
|
||||||
|
@override
|
||||||
|
BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
|
||||||
|
return BoxConstraints(
|
||||||
|
minWidth: menuSize.width,
|
||||||
|
maxWidth: menuSize.width,
|
||||||
|
minHeight: menuSize.height,
|
||||||
|
maxHeight: menuSize.height,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Offset getPositionForChild(Size size, Size childSize) {
|
||||||
|
Rect pop = Offset.zero & childSize;
|
||||||
|
pop.center;
|
||||||
|
return buttonRect.center -
|
||||||
|
pop.center +
|
||||||
|
Offset(
|
||||||
|
(childSize.width + buttonRect.width) * 0.5 * alignment.x,
|
||||||
|
(childSize.height + buttonRect.height) * 0.5 * alignment.y,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool shouldRelayout(_DropdownMenuLayoutDelegate oldDelegate) {
|
||||||
|
return buttonRect != oldDelegate.buttonRect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
name: flutter_date_time_picker
|
name: flutter_date_time_picker
|
||||||
description: A Flutter package for date and time picker.
|
description: A Flutter package for date and time picker.
|
||||||
version: 2.2.1
|
version: 2.2.2
|
||||||
homepage: https://iconica.nl/
|
homepage: https://iconica.nl/
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
|
|
Loading…
Reference in a new issue