Skip to main content

DatePickerAppi

A comprehensive date picker widget with custom styling, validation, and flexible display modes for Flutter applications.

Features

  • Multiple Display Modes: Popup dialog or custom overlay
  • Date Range Validation: Configurable first and last date limits
  • Form Integration: Full form validation support
  • Focus Management: Automatic focus handling and navigation
  • Custom Styling: Inherits from TextFieldAppi styling
  • Keyboard Support: Proper keyboard navigation and handling
  • Accessibility: Screen reader support and semantic labels
  • Flexible Date Ranges: Support for relative date ranges (e.g., years before current)

Usage

Basic Date Picker

DatePickerAppi(
textFieldStyle: TextFieldParamsAppi(
hint: 'Select Date',
widgetKey: GlobalKey<FormFieldState<String>>(),
),
onChange: (dateString) {
print('Selected date: $dateString');
},
)

Date Picker with Validation

DatePickerAppi(
textFieldStyle: TextFieldParamsAppi(
hint: 'Birth Date',
widgetKey: _birthDateKey,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please select your birth date';
}
return null;
},
mandatory: true,
),
onChange: (dateString) {
setState(() => _selectedBirthDate = dateString);
},
firstDate: DateTime(1900),
lastDate: DateTime.now(),
)

Date Picker with Custom Range

DatePickerAppi(
textFieldStyle: TextFieldParamsAppi(
hint: 'Appointment Date',
widgetKey: _appointmentDateKey,
heading: 'Select Appointment Date',
),
onChange: (dateString) {
_scheduleAppointment(dateString);
},
firstDate: DateTime.now(),
lastDate: DateTime.now().add(Duration(days: 365)),
initialDate: DateTime.now().add(Duration(days: 1)),
)

Date Picker with Years Before Current

DatePickerAppi(
textFieldStyle: TextFieldParamsAppi(
hint: 'Experience Start Date',
widgetKey: _experienceDateKey,
),
onChange: (dateString) {
_updateExperience(dateString);
},
beforeYear: 10, // Shows dates from 10 years ago
popup: true,
)

Parameters

NameTypeDescriptionDefault
textFieldStyleTextFieldParamsAppiRequired. Text field configuration and styling-
onChangeFunction(String)Required. Callback when date is selected-
initialDateDateTime?Initial date to show in pickerCurrent date or calculated from beforeYear
firstDateDateTime?Earliest selectable dateDateTime(1900)
lastDateDateTime?Latest selectable dateDateTime(2100)
popupboolWhether to show as popup dialogtrue
nextFocusNodeFocusNode?Focus node to move to after selectionnull
beforeYearint?Years before current year for initial datenull

TextFieldParamsAppi Integration

The DatePickerAppi uses TextFieldParamsAppi for all text field related configurations:

TextFieldParamsAppi(
// Basic properties
hint: 'Select Date',
heading: 'Date of Birth',
mandatory: true,

// Validation
validator: (value) => value?.isEmpty == true ? 'Required' : null,
widgetKey: GlobalKey<FormFieldState<String>>(),

// Styling
border: OutlineInputBorder(),
fillColor: Colors.white,
textStyle: TextStyle(fontSize: 16),

// Focus management
focus: FocusNode(),
)

Best Practices

  1. Date Ranges: Always set appropriate firstDate and lastDate for your use case
  2. Validation: Provide clear validation messages for required date fields
  3. Initial Values: Set sensible initial dates based on context
  4. Focus Management: Use nextFocusNode for smooth form navigation
  5. Accessibility: Provide meaningful hints and labels
  6. Error Handling: Handle edge cases like invalid date ranges
  7. User Experience: Use popup mode for better mobile experience

Examples

Birth Date Picker

DatePickerAppi(
textFieldStyle: TextFieldParamsAppi(
hint: 'DD/MM/YYYY',
heading: 'Date of Birth',
mandatory: true,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Birth date is required';
}
// Additional age validation
final selectedDate = DateTime.tryParse(value);
if (selectedDate != null) {
final age = DateTime.now().difference(selectedDate).inDays ~/ 365;
if (age < 18) {
return 'Must be at least 18 years old';
}
}
return null;
},
widgetKey: _birthDateKey,
),
onChange: (dateString) {
setState(() => _birthDate = dateString);
},
firstDate: DateTime(1900),
lastDate: DateTime.now().subtract(Duration(days: 365 * 18)), // 18 years ago
)

Event Date Picker

DatePickerAppi(
textFieldStyle: TextFieldParamsAppi(
hint: 'Select Event Date',
heading: 'Event Date',
prefixIcon: Icons.event,
widgetKey: _eventDateKey,
),
onChange: (dateString) {
_updateEventDate(dateString);
},
firstDate: DateTime.now(),
lastDate: DateTime.now().add(Duration(days: 365 * 2)),
initialDate: DateTime.now().add(Duration(days: 7)),
)

Form Integration

Form(
key: _formKey,
child: Column(
children: [
DatePickerAppi(
textFieldStyle: TextFieldParamsAppi(
hint: 'Start Date',
heading: 'Project Start Date',
mandatory: true,
validator: (value) => value?.isEmpty == true ? 'Start date required' : null,
widgetKey: _startDateKey,
focus: _startDateFocus,
),
onChange: (dateString) {
setState(() => _startDate = dateString);
_validateDateRange();
},
nextFocusNode: _endDateFocus,
),
SizedBox(height: 16),
DatePickerAppi(
textFieldStyle: TextFieldParamsAppi(
hint: 'End Date',
heading: 'Project End Date',
mandatory: true,
validator: (value) {
if (value?.isEmpty == true) return 'End date required';
if (_startDate.isNotEmpty && value != null) {
final start = DateTime.tryParse(_startDate);
final end = DateTime.tryParse(value);
if (start != null && end != null && end.isBefore(start)) {
return 'End date must be after start date';
}
}
return null;
},
widgetKey: _endDateKey,
focus: _endDateFocus,
),
onChange: (dateString) {
setState(() => _endDate = dateString);
_validateDateRange();
},
firstDate: _startDate.isNotEmpty ? DateTime.tryParse(_startDate) : DateTime.now(),
),
SizedBox(height: 24),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
_submitForm();
}
},
child: Text('Submit'),
),
],
),
)

Custom Styling

DatePickerAppi(
textFieldStyle: TextFieldParamsAppi(
hint: 'Select Date',
heading: 'Custom Styled Date',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(color: Colors.blue),
),
fillColor: Colors.blue.shade50,
textStyle: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
prefixIcon: Icons.calendar_today,
widgetKey: _customDateKey,
),
onChange: (dateString) {
_handleCustomDate(dateString);
},
)

See Also