I'm using table_calendar package to display a calendar on a page.
I want the user to be able to chose a date from the calendar, but when tapping on a date, the focusedDay won't change, so it always stays on the default focusedDay.
I tried to search the docs, and I can't figure out what is wrong, from the docs it seems like it should work fine.
This is what I have for the CalendarWidget:
TableCalendar(
focusedDay: _focusedDay,
firstDay: DateTime.now(),
lastDay: DateTime.utc(2030, 1, 1),
calendarFormat: CalendarFormat.month,
headerStyle: HeaderStyle(
formatButtonVisible: false,
titleCentered: true,
rightChevronIcon: Icon(
Icons.chevron_right,
size: 16,
color: Colors.grey,
),
leftChevronIcon: Icon(
Icons.chevron_left,
size: 16,
color: Colors.grey,
),
),
onDaySelected: (selectedDay, focusedDay) {
setState(() {
_selectedDay = selectedDay;
_focusedDay = focusedDay;
});
},
),
This is inside a stateful widget, and I have _focusdDay as a variable in that class, which I update.
The TableCalendar is of course inside the build function of that class.
Don't forget to define the selectedDayPredicate in your TableCalendar:
TableCalendar(
...
selectedDayPredicate: (day) =>isSameDay(day, selectedDay),
...
)
The widget will use this to find out which day is the selected day
Instead of Using this , You can Use DatePicker and Redesign it by Yourself
here is the Example :
onTap: () async {
DateTime newSelectedDate =
await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime.now(),
lastDate: DateTime(2100),
builder: (BuildContext context,
Widget child) {
return Theme(
data: ThemeData.dark().copyWith(
colorScheme: ColorScheme.dark(
primary: Colors.pink,
onPrimary: Colors.white,
surface: Colors.white,
onSurface: Colors.black,
),
dialogBackgroundColor:
Colors.grey[200],
),
child: child,
);
});
if (newSelectedDate != null) {
setState(() {
_selectedDate = newSelectedDate;
final DateFormat formatter =
DateFormat('yyyy-MM-dd');
formattedSelectedDate =
formatter.format(_selectedDate);
});
}
},
Related
What I want to do is listening to a stream which contains Lists of Events for each day of month.
I need this for my TableCalendar Widget
I want to count each Event of each list of the stream and display it in the calendar.
For this I wrote this function:
countEvents(DateTime datetime) {
eventBloc.getEventsOfDay(datetime).listen((event) {
counter = event.length;
});
}
This is where I execute the function (in markerBuilder):
StreamBuilder<List<Event>>(
stream: selectedEvents,
builder: (context, snapshot) {
if (snapshot.hasData) {
final events = snapshot.data;
groupEvents(allEventsList);
return Column(children: [
Card(
clipBehavior: Clip.antiAlias,
margin: const EdgeInsets.all(10),
elevation: 5,
child: TableCalendar(
firstDay: DateTime.utc(1970, 01, 01),
lastDay: DateTime.utc(2999, 12, 31),
focusedDay: _selectedDay,
locale: 'en_US',
onPageChanged: (focusedDay) {
_focusedDay = focusedDay;
},
selectedDayPredicate: (day) {
return isSameDay(_selectedDay, day);
},
headerStyle: HeaderStyle(
decoration: BoxDecoration(
color: AppColors.red,
),
headerMargin: const EdgeInsets.only(bottom: 10),
),
calendarStyle: CalendarStyle(),
calendarBuilders: CalendarBuilders(
markerBuilder: ((context, day, events) {
countEvents(day);
return Container(
width: 20,
height: 15,
decoration: BoxDecoration(
color: AppColors.red,
borderRadius: BorderRadius.circular(4.0)),
child: Text(counter.toString()),
);
})),
//Day Changed
onDaySelected: (DateTime selectDay, DateTime focusDay) {
setState(() {
_selectedDay = selectDay;
_focusedDay = focusDay;
selectedEvents =
eventBloc.getEventsOfDay(_selectedDay);
});
//print(_focusedDay);
},
startingDayOfWeek: StartingDayOfWeek.monday,
eventLoader: getEventsForDay,
),
counter is a global variable for the class
I used the debugger and it seems like the listen function is skipped all the time..
Thank you for your help!
I want to validating from date selection date to To date selction
date. I selected 17th July 2022 in FromDate and ToDate selection time
only show 4 days(17,18,19,20) how i show only 7 past dates in ToDate
Picker in flutter.
DateTime fromDate = DateTime.now();
TimeOfDay fromTime = TimeOfDay.now();
String selectedFromDateTime;
String selectedToDateTime;
DateTime toDate = DateTime.now();
TimeOfDay toTime = TimeOfDay.now();
Future<void> _showFromDateTimePicker() async {
final DateTime datePicked = await showDatePicker(
context: context,
initialDate: fromDate,
firstDate: DateTime(1900),
lastDate: DateTime.now(),builder: (context, child) {
return Theme(
data: ThemeData(
splashColor: AppTheme.card_bg,
colorScheme: ColorScheme.light(
primary: AppTheme.card_bg,
onSecondary: Colors.black,
onPrimary: Colors.white,
surface: Colors.black,
onSurface: Colors.black,
secondary: Colors.black),
dialogBackgroundColor: Colors.white,
),
child: child ?? Text(""),
);
},);
if (datePicked != null) {
final hour = fromTime.hour.toString().padLeft(2, "0");
final minute = fromTime.minute.toString().padLeft(2, "0");
final TimeOfDay timePicked =
await showTimePicker(context: context, initialTime: fromTime,builder: (context, child) {
return Theme(
data: ThemeData(
splashColor: AppTheme.card_bg,
colorScheme: ColorScheme.light(
primary: AppTheme.card_bg,
onSecondary: Colors.black,
onPrimary: Colors.white,
surface: Colors.white,
onSurface: Colors.black,
secondary: Colors.black),
dialogBackgroundColor: Colors.white,
),
child: child ?? Text(""),
);
},);
if (timePicked != null) {
setState(() {
selectedFromDateTime =
"${DateFormat("yyyy-MM-dd").format(datePicked)} $hour:$minute" +
":00";
});
}
}
}
Future<void> _showToDateTimePicker() async {
final DateTime datePicked = await showDatePicker(
context: context,
initialDate: toDate,
firstDate: DateTime.now(),
lastDate: DateTime.now(),
builder: (context, child) {
return Theme(
data: ThemeData(
splashColor: AppTheme.card_bg,
colorScheme: ColorScheme.light(
primary: AppTheme.card_bg,
onSecondary: Colors.black,
onPrimary: Colors.white,
surface: Colors.black,
onSurface: Colors.black,
secondary: Colors.black),
dialogBackgroundColor: Colors.white,
),
child: child ?? Text(""),
);
},
);
if (datePicked != null) {
final hour = toTime.hour.toString().padLeft(2, "0");
final minute = toTime.minute.toString().padLeft(2, "0");
final TimeOfDay timePicked = await showTimePicker(
context: context,
initialTime: toTime,
builder: (context, child) {
return Theme(
data: ThemeData(
splashColor: AppTheme.card_bg,
colorScheme: ColorScheme.light(
primary: AppTheme.card_bg,
onSecondary: Colors.black,
onPrimary: Colors.white,
surface: Colors.white,
onSurface: Colors.black,
secondary: Colors.black),
dialogBackgroundColor: Colors.white,
),
child: child ?? Text(""),
);
},
);
if (timePicked != null) {
setState(() {
selectedToDateTime =
"${DateFormat("yyyy-MM-dd").format(datePicked)} $hour:$minute" +
":00";
});
}
}
}
It's quite easy to do, you just need to subtract 7 days from today.
final sevenDaysBeforeToday =DateTime.now().subtract(Duration(days: 7));
and change firstDate to sevenDaysBeforeToday of showDatePicker
firstDate: sevenDaysBeforeToday,
I have the following calendar and code. How can I have the month be only 3 letters eg Nov 2021 instead of November 2021.
Container(
height: MediaQuery.of(context).size.height*0.3,
// width: MediaQuery.of(context).size.width*0.3,
color: Colors.white,
child: TableCalendar(
headerStyle: HeaderStyle(
titleTextStyle: TextStyle(fontSize: 12)
),
shouldFillViewport: true,
rowHeight:MediaQuery.of(context).size.height*0.02,
firstDay: DateTime.utc(2010, 10, 16),
lastDay: DateTime.utc(2030, 3, 14),
focusedDay: DateTime.now(),
onDaySelected: (selectedDay, focusedDay) {
if (!isSameDay(_selectedDay, selectedDay)) {
// Call `setState()` when updating the selected day
setState(() {
_selectedDay = selectedDay;
_focusedDay = focusedDay;
});
}
}
),
),
I achieved a responsive table with the customisation I wanted using this code:
Container(
height: MediaQuery.of(context).size.height*0.3,
color: Colors.white,
child: TableCalendar(
calendarStyle: CalendarStyle(
todayTextStyle: TextStyle(fontSize: MediaQuery.of(context).size.width*0.008,color: Colors.white),
weekendTextStyle: TextStyle(fontSize: MediaQuery.of(context).size.width*0.008),
outsideTextStyle: TextStyle(fontSize: MediaQuery.of(context).size.width*0.008),
defaultTextStyle: TextStyle(
fontSize: MediaQuery.of(context).size.width*0.008
)
) ,
headerStyle: HeaderStyle(
titleCentered: true,
titleTextFormatter: (date, locale) => DateFormat.yMMM(locale).format(date),
formatButtonVisible: false,
titleTextStyle: TextStyle(fontSize: MediaQuery.of(context).size.width*0.007)
),
shouldFillViewport: true,
rowHeight:MediaQuery.of(context).size.height*0.02,
firstDay: DateTime.utc(2010, 10, 16),
lastDay: DateTime.utc(2030, 3, 14),
focusedDay: DateTime.now(),
onDaySelected: (selectedDay, focusedDay) {
if (!isSameDay(_selectedDay, selectedDay)) {
// Call `setState()` when updating the selected day
setState(() {
_selectedDay = selectedDay;
_focusedDay = focusedDay;
});
}
}
),
),
as new table_calender 3.0.8 to disable two weeks/format button you can set
availableCalendarFormats: const {
CalendarFormat.month : 'Month'
}
and to center the title you also need to set up
headerStyle: HeaderStyle(
titleCentered: true
)
To remove 2 weeks use different calendarFormat
To change Header titile use titleTextFormatter
And finally play with PositionedOffset to control positions.
** Everything that is possible to change is documented here: https://pub.dev/documentation/table_calendar/latest/table_calendar/table_calendar-library.html
I am trying to get the value of the selected time and date when the Datepicker is shown.
I achieved the UI and shown the date and time picker when onTap.
The problem is that I can get the value after selected. The idea would be to render it somewhere in the screen as follows:
time selected: .....
date selected: .....
This is my code regarding the popUp of the DayPicker and the function that gets the value:
function and variables:
DateTime? _dateTime;
TimeOfDay _time = TimeOfDay(hour: 7, minute: 15);
void _selectTime() async {
final newTime = await showTimePicker(
context: context,
initialTime: _time,
initialEntryMode: TimePickerEntryMode.input,
);
if (newTime != null) {
setState(() {
_time = newTime;
});
}
}
Gesture Detector to show the PickerDate:
GestureDetector(
onTap: () {
showDatePicker(
context: context,
initialDate: _dateTime ?? DateTime.now(),
firstDate: DateTime(2021),
lastDate: DateTime(2023),
builder: (BuildContext context, Widget? child) {
return Theme(
data: ThemeData.light().copyWith(
primaryColor: context.themeSettings.lightRed,
accentColor: context.themeSettings.lightRed,
colorScheme: ColorScheme.light(primary: context.themeSettings.lightRed),
buttonTheme: ButtonThemeData(textTheme: ButtonTextTheme.primary),
),
child: child!,
);
},
).then(
(date) {
setState(
() {
_dateTime = date;
},
);
print('date');
},
);
},
Gesture detector to show the DatePicker:
GestureDetector(
onTap: _selectTime,
child: Container(
decoration: BoxDecoration(
border: Border.all(color: context.themeSettings.mediumGray),
borderRadius: BorderRadius.all(Radius.circular(
5.0,
) //
),
),
width: width * 0.40,
height: height * 0.05,
child: Center(
child: Text(
'Pick a time',
style: TextStyle(fontSize: 18, color: context.themeSettings.darkText, fontWeight: FontWeight.bold),
),
),
),
),
The only thing missing is to show the actual value selected for both information.
what am I missing?
It remains only to display the time for the user. With Text().
Your time value in the _time variable
and dates in _dateTime
Text("time selected: $_time date selected: _dateTime",),
put this somewhere in your interface
for example in a child in GestureDetector
upd (24.08.2021):
I can not understand what your problem may be, according to the code fragments that you showed
Try to use code close to this
Source of code
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(primarySwatch: Colors.blue, brightness: Brightness.dark),
home: DatePickerDemo(),
);
}
}
class DatePickerDemo extends StatefulWidget {
#override
_DatePickerDemoState createState() => _DatePickerDemoState();
}
class _DatePickerDemoState extends State<DatePickerDemo> {
/// Which holds the selected date
/// Defaults to today's date.
DateTime selectedDate = DateTime.now();
_selectDate(BuildContext context) async {
final DateTime picked = await showDatePicker(
context: context,
initialDate: selectedDate,
firstDate: DateTime(2000),
lastDate: DateTime(2025),
);
if (picked != null && picked != selectedDate)
setState(() {
selectedDate = picked;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
"${selectedDate.toLocal()}".split(' ')[0],
style: TextStyle(fontSize: 55, fontWeight: FontWeight.bold),
),
SizedBox(
height: 20.0,
),
ElevatedButton(
onPressed: () => _selectDate(context),
child: Text(
'Select date',
style:
TextStyle(color: Colors.black, fontWeight: FontWeight.bold),
),
),
],
),
),
);
}
}
Want to change the TextStyle of helpText in showDateRangePicker() in Flutter.
Can anybody Help.
buildMaterialDatePicker({BuildContext context, SearchVM model})
async {
final DateTimeRange picked = await showDateRangePicker(
context: context,
firstDate: initialDate,
helpText: 'Select a Date or Date-Range',
fieldStartHintText: 'Start Booking date',
fieldEndHintText: 'End Booking date',
currentDate: initialDate,
lastDate: DateTime(2020, initialDate.month + 1,
initialDate.day),
builder: (BuildContext context, Widget child) {
return Theme(
data: ThemeData.dark().copyWith(
colorScheme: ColorScheme.dark(
primary: Colors.greenAccent,
onPrimary: oppColor,
surface: Colors.greenAccent,
onSurface: oppColor,
),
dialogBackgroundColor: mainColor,
),
child: child,
);
},
);
}
So, according to the answer of abbas jafary answer.
I deep Dived into the Documentation of the showDateRangePicker() (you can do so using Ctrl+ Right-Clicking) and found what texstTheme it is using for that Text.
Text(
helpText,
style: textTheme.overline.apply(
color: headerForeground,),
),
So, Then I wrapped my Widget with Theme and updated the textTheme field.
buildMaterialDatePicker({BuildContext context, SearchVM model}) async {
final DateTimeRange picked = await showDateRangePicker(
context: context,
firstDate: initialDate,
helpText: 'Select a Date or Date-Range',
fieldStartHintText: 'Start Booking date',
fieldEndHintText: 'End Booking date',
currentDate: initialDate,
lastDate: DateTime(2020, initialDate.month + 1, initialDate.day),
builder: (BuildContext context, Widget child) {
return Theme(
data: ThemeData.dark().copyWith(
colorScheme: ColorScheme.dark(
primary: Colors.greenAccent,
onPrimary: oppColor,
surface: Colors.greenAccent,
onSurface: oppColor,
),
// Here I Chaged the overline to my Custom TextStyle.
textTheme: TextTheme(overline: TextStyle(fontSize: 16)),
dialogBackgroundColor: mainColor,
),
child: child,
);
},
);
}
For change colors, font and etc. You must wrap element into Theme:
Widget returnRangePicker(BuildContext context) {
return Theme(
data: Theme.of(context).copyWith(
accentColor: Colors.green,
primaryColor: Colors.blue,
buttonTheme: ButtonThemeData(
highlightColor: Colors.green,
buttonColor: Colors.green,
colorScheme: Theme.of(context).colorScheme.copyWith(
secondary: epapGreen,
background: Colors.white,
primary: Colors.green,
primaryVariant: Colors.green,
brightness: Brightness.dark,
onBackground: Colors.green),
textTheme: ButtonTextTheme.accent)),
child: Builder(
builder: (context) => FlatButton(
onPressed: () async {
final List<DateTime> picked = await DateRangePicker.showDatePicker(
context: context,
initialFirstDate: DateTime.now(),
initialLastDate:
DateTime.now()).add(Duration(days: 7),
firstDate: DateTime(2015),
lastDate: DateTime(2020));
if (picked != null && picked.length == 2) {
print(picked);
}
},
child: Text(
"Choose range",
style: TextStyle(color: Colors.green),
),
),
),
);
}
For more info you can check out the docs. or check this link