There is a simple date picker widget built into Flutter - called DateRangePickerDialog
.
I'd like to select a starting hour and a finishing hour of an event.
Where can I find a ready widget for that?
Asked
Active
Viewed 816 times
1

kosiara - Bartosz Kosarzycki
- 10,922
- 12
- 70
- 83
1 Answers
1
Use the following code which provides a simple TimeRangePickerDialog
.
You can customize opening hours. The result is available in
Availability.periodStartIndex
& Availability.periodStopIndex
Availability availability = Availability(
date: DateTime.now(), reservationFrom: 9, reservationTo: 21,
available: [9, 10,11,12,13,14,15,16,17,19,20,21,22
]);
@override
Widget build(BuildContext context) {
return TimeRangePickerDialog(availability, 4, 4, 40);
}
TimeRangePickerDialog
import 'package:flutter/material.dart';
import 'availability.dart';
import 'picker_single_hour.dart';
class TimeRangePickerDialog extends StatefulWidget {
final Availability data;
final double crossAxisSpacing;
final int crossAxisCount;
final double cellHeight;
TimeRangePickerDialog(
this.data,
this.crossAxisSpacing,
this.crossAxisCount,
this.cellHeight);
@override
State<TimeRangePickerDialog> createState() => _TimeRangePickerDialogState(
data, crossAxisSpacing, crossAxisCount, cellHeight
);
}
class _TimeRangePickerDialogState extends State<TimeRangePickerDialog> {
final Availability data;
final double crossAxisSpacing;
final int crossAxisCount;
final double cellHeight;
_TimeRangePickerDialogState(this.data, this.crossAxisSpacing, this.crossAxisCount, this.cellHeight);
@override
Widget build(BuildContext context) {
final _screenWidth = MediaQuery.of(context).size.width;
final _width = (_screenWidth - ((crossAxisCount - 1) * crossAxisSpacing)) /
crossAxisCount;
final _aspectRatio = _width / cellHeight;
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: crossAxisCount, childAspectRatio: _aspectRatio),
itemCount: data.hours.length,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, index) => GestureDetector(
onTap: () {
setState(() {
handleSelection(data, index);
});
},
child: HourPickerSingleHour(
selectAppropriateItemState(data, index),
data.hours[index].time,
data.date.param,
data.hours[index].time,
data.hours[index].availability
),
));
}
void handleSelection(Availability data, int index) {
if (data.periodStartIndex == null && data.periodEndIndex == null)
data.periodStartIndex = index;
else if (data.periodStartIndex != null && data.periodEndIndex == null) {
data.periodEndIndex = index;
// prevent selection of hours in wrong order
if (data.periodStartIndex != null && data.periodEndIndex != null &&
data.periodStartIndex! > data.periodEndIndex!) {
data.periodStartIndex = null;
data.periodEndIndex = null;
}
}
else {
data.periodStartIndex = null;
data.periodEndIndex = null;
}
}
HourPickerHourState selectAppropriateItemState(Availability data, int index) {
if (data.periodStartIndex == index)
return HourPickerHourState.START;
else if (data.periodEndIndex == index)
return HourPickerHourState.END;
else if (data.periodStartIndex != null && data.periodEndIndex != null &&
data.periodStartIndex! < data.periodEndIndex! &&
index < data.periodEndIndex! && index > data.periodStartIndex!)
return HourPickerHourState.MIDDLE;
else return HourPickerHourState.EMPTY;
}
}
HourPickerSingleHour
enum HourPickerHourState {
START,
MIDDLE,
END,
EMPTY
}
class HourPickerSingleHour extends StatelessWidget {
final double START_END_CIRCLE_RADIUS = 16;
final double START_END_PERIOD_MARGIN = 12;
final HourPickerHourState state;
final String timeHeader;
final String dateParam;
final String dateTime;
final bool hoursAvailability;
const HourPickerSingleHour(
this.state,
this.timeHeader,
this.dateParam,
this.dateTime,
this.hoursAvailability);
@override
Widget build(BuildContext context) {
EdgeInsets margin = EdgeInsets.only(
left: state == HourPickerHourState.START ? START_END_PERIOD_MARGIN : 0,
right: state == HourPickerHourState.END ? START_END_PERIOD_MARGIN : 0,
bottom: 0,
top: 0,
);
Color backgroundColor = Color.fromARGB(
state == HourPickerHourState.EMPTY ? 0 : 35, 0, 0, 255);
return Container(
margin: margin,
decoration: BoxDecoration(
color: backgroundColor,
borderRadius: BorderRadius.only(
topLeft: state == HourPickerHourState.START ? Radius.circular(START_END_CIRCLE_RADIUS) : Radius.circular(0),
bottomLeft: state == HourPickerHourState.START ? Radius.circular(START_END_CIRCLE_RADIUS) : Radius.circular(0),
topRight: state == HourPickerHourState.END ? Radius.circular(START_END_CIRCLE_RADIUS) : Radius.circular(0),
bottomRight: state == HourPickerHourState.END ? Radius.circular(START_END_CIRCLE_RADIUS) : Radius.circular(0),
)
),
alignment: Alignment.center,
child: Text(
timeHeader,
key: Key(
'text_dayHour_${dateParam}_${dateTime}'),
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'SofiaPro',
fontSize: 16,
color: hoursAvailability
? Colors.grey
: Colors.blueGrey),
),
);
}
}
Availability
import 'package:intl/intl.dart';
import 'hour_availability.dart';
class Availability {
DateTime date;
int reservationFrom;
int reservationTo;
List<int> available;
int? periodStartIndex;
int? periodEndIndex;
Availability(
{required this.date,
required this.reservationFrom,
required this.reservationTo,
required this.available});
List<HourAvailability> get hours {
final now = DateTime.now();
List<HourAvailability> list = [];
for (var i = reservationFrom; i <= reservationTo; i++) {
String time = DateTime(now.year, now.month, now.day, i, 0).time;
list.add(HourAvailability(i, time, _specifyAvailability(i)));
}
return list;
}
bool _specifyAvailability(int i) =>
available.contains(i) ||
(i == reservationTo &&
available.isNotEmpty &&
available.last == (reservationTo - 1));
}
extension DateTimeFormat on DateTime {
String get param => DateFormat('yyyy-MM-dd').format(this);
String get time => DateFormat('hh:mm a').format(this);
}
HourAvailability
class HourAvailability {
final int hour;
final String time;
final bool availability;
HourAvailability(this.hour, this.time, this.availability);
}

kosiara - Bartosz Kosarzycki
- 10,922
- 12
- 70
- 83
-
I think your answer would be improved by a demo. It is a lot of code to just be trying out at once. – David Jentjens Jun 14 '22 at 12:08