From a3fcfabb0127a7049691718b09fdaec34e85de25 Mon Sep 17 00:00:00 2001 From: Brighton van den End Date: Mon, 21 Nov 2022 14:53:07 +0100 Subject: [PATCH] fix red screen of death caused by overlay not disposing --- example/lib/main.dart | 158 +++++++++--------- lib/src/models/date_time_picker_theme.dart | 6 +- lib/src/overlay_date_time_picker.dart | 22 +-- .../overlay_date_time_picker/overlay.dart | 52 ++++-- 4 files changed, 134 insertions(+), 104 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 7810afd..173e855 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -20,12 +20,7 @@ class MyApp extends StatelessWidget { theme: ThemeData( primarySwatch: Colors.blue, ), - home: Scaffold( - appBar: AppBar( - title: const Text('Demo'), - ), - body: const DatePickerDemo(), - ), + home: const DatePickerDemo(), ); } } @@ -58,86 +53,99 @@ class DatePickerDemo extends StatelessWidget { barColor: Colors.black, barOpacity: 1, ), + paginationSize: 50, ); - return Stack( - children: [ - Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - OverlayDateTimePicker( - theme: dateTimePickerTheme, - alignment: Alignment.bottomCenter, - child: const Text("Select Day"), - onTapDay: (date) {}, - ), - OverlayDateTimePicker( - theme: dateTimePickerTheme, - alignment: Alignment.center, - buttonBuilder: (key, onPressed) => TextButton( - key: key, - onPressed: onPressed, + return Scaffold( + appBar: AppBar( + automaticallyImplyLeading: true, + title: const Text('Demo'), + ), + body: Stack( + children: [ + Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + OverlayDateTimePicker( + theme: dateTimePickerTheme, + alignment: Alignment.bottomCenter, child: const Text("Select Day"), + onTapDay: (date) {}, ), - dateTimeConstraint: DateTimeConstraint( - min: DateConstraint(date: DateTime.now()), - ), - ), - OverlayDateTimePicker( - theme: dateTimePickerTheme, - alignment: Alignment.topCenter, - buttonBuilder: (key, onPressed) => IconButton( - key: key, - onPressed: onPressed, - icon: const Icon( - Icons.schedule, + OverlayDateTimePicker( + theme: dateTimePickerTheme, + alignment: Alignment.center, + buttonBuilder: (key, onPressed) => TextButton( + key: key, + onPressed: onPressed, + child: const Text("Select Day"), + ), + dateTimeConstraint: DateTimeConstraint( + min: DateConstraint(date: DateTime.now()), ), ), - dateTimeConstraint: DateTimeConstraint( - min: DateConstraint(date: DateTime.now()), - max: DateConstraint( - date: DateTime( - DateTime.now().year, - DateTime.now().month + 4, - DateTime.now().day, + OverlayDateTimePicker( + theme: dateTimePickerTheme, + alignment: Alignment.topCenter, + buttonBuilder: (key, onPressed) => IconButton( + key: key, + onPressed: onPressed, + icon: const Icon( + Icons.schedule, ), ), + dateTimeConstraint: DateTimeConstraint( + min: DateConstraint(date: DateTime.now()), + max: DateConstraint( + date: DateTime( + DateTime.now().year, + DateTime.now().month + 4, + DateTime.now().day, + ), + ), + ), + onNextPageButtonBuilder: (onPressed) { + return IconButton( + onPressed: onPressed, icon: const Icon(Icons.add)); + }, + onPreviousPageButtonBuilder: (onPressed) { + return IconButton( + onPressed: onPressed, icon: const Icon(Icons.minimize)); + }, + ) + ], + ), + ), + DragDownDateTimePicker( + dateTimePickerTheme: const DateTimePickerTheme( + backgroundColor: Colors.white, + markedIndicatorColor: Colors.red, + baseTheme: DateBoxBaseTheme( + Colors.white, + TextStyle(color: Colors.black), + ), + selectedTheme: DateBoxSelectedTheme( + Color(0x4BF44336), + TextStyle( + color: Colors.red, ), - onNextPageButtonChild: const Icon(Icons.add), - onPreviousPageButtonChild: const Icon(Icons.minimize), - ) - ], - ), - ), - DragDownDateTimePicker( - dateTimePickerTheme: const DateTimePickerTheme( - backgroundColor: Colors.white, - markedIndicatorColor: Colors.red, - baseTheme: DateBoxBaseTheme( - Colors.white, - TextStyle(color: Colors.black), - ), - selectedTheme: DateBoxSelectedTheme( - Color(0x4BF44336), - TextStyle( - color: Colors.red, + ), + highlightTheme: DateBoxHighlightTheme( + Colors.red, + TextStyle( + color: Colors.white, + ), + ), + barTheme: DateTimePickerBarTheme( + barColor: Colors.black, + barOpacity: 1, ), ), - highlightTheme: DateBoxHighlightTheme( - Colors.red, - TextStyle( - color: Colors.white, - ), - ), - barTheme: DateTimePickerBarTheme( - barColor: Colors.black, - barOpacity: 1, - ), - ), - markedDates: [DateTime(2022, 9, 6)], - ) - ], + markedDates: [DateTime(2022, 9, 6)], + ) + ], + ), ); } } diff --git a/lib/src/models/date_time_picker_theme.dart b/lib/src/models/date_time_picker_theme.dart index e573180..bec6d5d 100644 --- a/lib/src/models/date_time_picker_theme.dart +++ b/lib/src/models/date_time_picker_theme.dart @@ -7,8 +7,9 @@ import 'package:flutter_date_time_picker/flutter_date_time_picker.dart'; class DateTimePickerTheme { /// The [DateTimePickerTheme] to style [DragDownDateTimePicker] in. Define a custom shape for the dates and specifically style - /// a basic, hightlighted, selected and disabled date. + /// a basic, highlighted, selected and disabled date. const DateTimePickerTheme({ + this.paginationSize = 25, this.weekDateBoxSize = 35, this.monthDateBoxSize = 45, this.markedIndicatorColor, @@ -75,4 +76,7 @@ class DateTimePickerTheme { /// The position where the week view changes to month view and the other way around. Enter a value between 0 and 1 that's between the weekViewSize and the monthViewSize. final double weekMonthTriggerSize; + + /// The size of the buttons for navigation the different pages + final double paginationSize; } diff --git a/lib/src/overlay_date_time_picker.dart b/lib/src/overlay_date_time_picker.dart index ea8bdea..27bc7b2 100644 --- a/lib/src/overlay_date_time_picker.dart +++ b/lib/src/overlay_date_time_picker.dart @@ -29,8 +29,8 @@ class OverlayDateTimePicker extends StatefulWidget { this.closeOnSelectDate = true, this.showWeekDays = true, this.dateTimeConstraint = const DateTimeConstraint(), - this.onNextPageButtonChild, - this.onPreviousPageButtonChild, + this.onNextPageButtonBuilder, + this.onPreviousPageButtonBuilder, }) : assert(child != null || buttonBuilder != null); /// The child contained by the DatePicker. @@ -84,11 +84,12 @@ class OverlayDateTimePicker extends StatefulWidget { /// a [DateTimeConstraint] that dictates the constraints of the dates that can be picked. final DateTimeConstraint dateTimeConstraint; - /// a [Widget] that determents the icon of the button for going to the next page - final Widget? onNextPageButtonChild; + /// a [Function] that determents the icon of the button for going to the next page + final Widget Function(void Function()? onPressed)? onNextPageButtonBuilder; - /// a [Widget] that determents the icon of the button for going to the previous page - final Widget? onPreviousPageButtonChild; + /// a [Function] that determents the icon of the button for going to the previous page + final Widget Function(void Function()? onPressed)? + onPreviousPageButtonBuilder; @override State createState() => _OverlayDateTimePickerState(); @@ -144,14 +145,15 @@ class _OverlayDateTimePickerState extends State { @override void dispose() { + if (_overlay.mounted) _overlay.remove(); _overlay.dispose(); - _overlayState?.dispose(); + _overlayState = null; _dateTimePickerController.dispose(); super.dispose(); } void _toggleOverlay() { - if (mounted) { + if (mounted && (_overlayState?.mounted ?? false)) { setState(() { if (!_isShown) { _overlayState?.insert(_overlay); @@ -232,8 +234,8 @@ class _OverlayDateTimePickerState extends State { onNextDate: nextDate, onPreviousDate: previousDate, dateTimeConstraint: widget.dateTimeConstraint, - onNextPageButtonChild: widget.onNextPageButtonChild, - onPreviousPageButtonChild: widget.onPreviousPageButtonChild, + onNextPageButtonChild: widget.onNextPageButtonBuilder, + onPreviousPageButtonChild: widget.onPreviousPageButtonBuilder, ), ), ), diff --git a/lib/src/widgets/overlay_date_time_picker/overlay.dart b/lib/src/widgets/overlay_date_time_picker/overlay.dart index 7b3a3e6..a1a2ac0 100644 --- a/lib/src/widgets/overlay_date_time_picker/overlay.dart +++ b/lib/src/widgets/overlay_date_time_picker/overlay.dart @@ -32,8 +32,8 @@ class OverlayDateTimeContent extends StatefulWidget { final bool showWeekDays; final DateTimeConstraint dateTimeConstraint; - final Widget? onNextPageButtonChild; - final Widget? onPreviousPageButtonChild; + final Widget Function(void Function()? onPressed)? onNextPageButtonChild; + final Widget Function(void Function()? onPressed)? onPreviousPageButtonChild; final void Function() onNextDate; final void Function() onPreviousDate; @@ -77,28 +77,42 @@ class _OverlayDateTimeContentState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - IconButton( - onPressed: (widget.dateTimeConstraint.inMonthRange(previousDate)) - ? _goToPreviousPage - : null, - icon: widget.onPreviousPageButtonChild ?? - const Icon(Icons.arrow_circle_left_outlined), - color: widget.theme.barTheme.barColor, - ), + (widget.onPreviousPageButtonChild != null) + ? widget.onPreviousPageButtonChild!( + (widget.dateTimeConstraint.inMonthRange(previousDate)) + ? _goToPreviousPage + : null, + ) + : IconButton( + onPressed: + (widget.dateTimeConstraint.inMonthRange(previousDate)) + ? _goToPreviousPage + : null, + icon: const Icon(Icons.arrow_circle_left_outlined), + color: widget.theme.barTheme.barColor, + iconSize: widget.theme.paginationSize, + ), Text( DateFormat.yMMMM().format( widget.controller.browsingDate, ), style: widget.theme.baseTheme.textStyle, ), - IconButton( - onPressed: (widget.dateTimeConstraint.inMonthRange(nextDate)) - ? _goToNextPage - : null, - icon: widget.onNextPageButtonChild ?? - const Icon(Icons.arrow_circle_right_outlined), - color: widget.theme.barTheme.barColor, - ), + (widget.onNextPageButtonChild != null) + ? widget.onNextPageButtonChild!( + (widget.dateTimeConstraint.inMonthRange(nextDate)) + ? _goToNextPage + : null, + ) + : IconButton( + onPressed: + (widget.dateTimeConstraint.inMonthRange(nextDate)) + ? _goToNextPage + : null, + icon: const Icon(Icons.arrow_circle_right_outlined), + color: widget.theme.barTheme.barColor, + iconSize: widget.theme.paginationSize, + ), ], ), Container( @@ -158,6 +172,7 @@ class _OverlayDateTimeContentState extends State { } void _goToNextPage() async { + if (!mounted) return; setState(() { usesButtons = true; }); @@ -169,6 +184,7 @@ class _OverlayDateTimeContentState extends State { } void _goToPreviousPage() async { + if (!mounted) return; setState(() { usesButtons = true; });