272 lines
7.7 KiB
Dart
272 lines
7.7 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:intl/intl.dart';
|
|
|
|
class CustomDatePicker extends StatefulWidget {
|
|
final DateTime initialDate;
|
|
final DateTime firstDate;
|
|
final DateTime lastDate;
|
|
final String currentDateText;
|
|
|
|
CustomDatePicker({
|
|
required this.initialDate,
|
|
required this.firstDate,
|
|
required this.lastDate,
|
|
required this.currentDateText,
|
|
});
|
|
|
|
@override
|
|
_CustomDatePickerState createState() => _CustomDatePickerState();
|
|
}
|
|
|
|
class _CustomDatePickerState extends State<CustomDatePicker> {
|
|
late DateTime _selectedDate;
|
|
late int _selectedYear;
|
|
late int _selectedMonth;
|
|
late int _selectedDay;
|
|
late ScrollController _yearScrollController;
|
|
late ScrollController _monthScrollController;
|
|
late ScrollController _dayScrollController;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_selectedDate = _parseDate(widget.currentDateText) ?? widget.initialDate;
|
|
_selectedYear = _selectedDate.year;
|
|
_selectedMonth = _selectedDate.month;
|
|
_selectedDay = _selectedDate.day;
|
|
|
|
_yearScrollController = ScrollController(
|
|
initialScrollOffset: (_selectedYear - widget.firstDate.year) * 70.0,
|
|
);
|
|
_monthScrollController = ScrollController(
|
|
initialScrollOffset: (_selectedMonth - 1) * 50.0,
|
|
);
|
|
_dayScrollController = ScrollController(
|
|
initialScrollOffset: (_selectedDay - 1) * 50.0,
|
|
);
|
|
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
_centerSelectedYear();
|
|
_centerSelectedMonth();
|
|
_centerSelectedDay();
|
|
});
|
|
}
|
|
|
|
void _centerSelectedYear() {
|
|
final screenWidth = MediaQuery.of(context).size.width;
|
|
final centerPosition = (_selectedYear - widget.firstDate.year) * 70.0 - (screenWidth / 2) + 35.0;
|
|
_yearScrollController.animateTo(
|
|
centerPosition,
|
|
duration: Duration(milliseconds: 300),
|
|
curve: Curves.easeInOut,
|
|
);
|
|
}
|
|
|
|
void _centerSelectedMonth() {
|
|
final screenWidth = MediaQuery.of(context).size.width;
|
|
final centerPosition = (_selectedMonth - 1) * 50.0 - (screenWidth / 2) + 25.0;
|
|
_monthScrollController.animateTo(
|
|
centerPosition,
|
|
duration: Duration(milliseconds: 300),
|
|
curve: Curves.easeInOut,
|
|
);
|
|
}
|
|
|
|
void _centerSelectedDay() {
|
|
final screenWidth = MediaQuery.of(context).size.width;
|
|
final centerPosition = (_selectedDay - 1) * 50.0 - (screenWidth / 2) + 25.0;
|
|
_dayScrollController.animateTo(
|
|
centerPosition,
|
|
duration: Duration(milliseconds: 300),
|
|
curve: Curves.easeInOut,
|
|
);
|
|
}
|
|
|
|
DateTime? _parseDate(String dateString) {
|
|
try {
|
|
return DateFormat('yyyy/MM/dd').parse(dateString);
|
|
} catch (e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Dialog(
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: <Widget>[
|
|
Padding(
|
|
padding: const EdgeInsets.all(16.0),
|
|
child: Text(
|
|
'生年月日の選択',
|
|
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
|
),
|
|
),
|
|
_buildLabeledPicker('年', _buildYearPicker()),
|
|
_buildLabeledPicker('月', _buildMonthPicker()),
|
|
_buildLabeledPicker('日', _buildDayPicker()),
|
|
_buildActionButtons(),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildLabeledPicker(String label, Widget picker) {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Padding(
|
|
padding: const EdgeInsets.only(left: 16.0, top: 8.0),
|
|
child: Text(label, style: TextStyle(fontWeight: FontWeight.bold)),
|
|
),
|
|
picker,
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _buildYearPicker() {
|
|
return Container(
|
|
height: 100,
|
|
child: ListView.builder(
|
|
controller: _yearScrollController,
|
|
scrollDirection: Axis.horizontal,
|
|
itemCount: widget.lastDate.year - widget.firstDate.year + 1,
|
|
itemBuilder: (context, index) {
|
|
final year = widget.firstDate.year + index;
|
|
return GestureDetector(
|
|
onTap: () {
|
|
setState(() {
|
|
_selectedYear = year;
|
|
_updateSelectedDate();
|
|
_centerSelectedYear();
|
|
});
|
|
},
|
|
child: Container(
|
|
width: 70,
|
|
padding: EdgeInsets.all(8),
|
|
alignment: Alignment.center,
|
|
decoration: BoxDecoration(
|
|
color: _selectedYear == year ? Colors.blue : null,
|
|
borderRadius: BorderRadius.circular(4),
|
|
),
|
|
child: Text(
|
|
year.toString(),
|
|
style: TextStyle(
|
|
color: _selectedYear == year ? Colors.white : null,
|
|
),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildMonthPicker() {
|
|
return Container(
|
|
height: 50,
|
|
child: ListView.builder(
|
|
controller: _monthScrollController,
|
|
scrollDirection: Axis.horizontal,
|
|
itemCount: 12,
|
|
itemBuilder: (context, index) {
|
|
final month = index + 1;
|
|
return GestureDetector(
|
|
onTap: () {
|
|
setState(() {
|
|
_selectedMonth = month;
|
|
_updateSelectedDate();
|
|
_centerSelectedMonth();
|
|
});
|
|
},
|
|
child: Container(
|
|
width: 50,
|
|
padding: EdgeInsets.all(8),
|
|
alignment: Alignment.center,
|
|
decoration: BoxDecoration(
|
|
color: _selectedMonth == month ? Colors.blue : null,
|
|
borderRadius: BorderRadius.circular(4),
|
|
),
|
|
child: Text(
|
|
month.toString(),
|
|
style: TextStyle(
|
|
color: _selectedMonth == month ? Colors.white : null,
|
|
),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildDayPicker() {
|
|
final daysInMonth = DateTime(_selectedYear, _selectedMonth + 1, 0).day;
|
|
return Container(
|
|
height: 50,
|
|
child: ListView.builder(
|
|
controller: _dayScrollController,
|
|
scrollDirection: Axis.horizontal,
|
|
itemCount: daysInMonth,
|
|
itemBuilder: (context, index) {
|
|
final day = index + 1;
|
|
return GestureDetector(
|
|
onTap: () {
|
|
setState(() {
|
|
_selectedDay = day;
|
|
_updateSelectedDate();
|
|
_centerSelectedDay();
|
|
});
|
|
},
|
|
child: Container(
|
|
width: 50,
|
|
padding: EdgeInsets.all(8),
|
|
alignment: Alignment.center,
|
|
decoration: BoxDecoration(
|
|
color: _selectedDay == day ? Colors.blue : null,
|
|
borderRadius: BorderRadius.circular(4),
|
|
),
|
|
child: Text(
|
|
day.toString(),
|
|
style: TextStyle(
|
|
color: _selectedDay == day ? Colors.white : null,
|
|
),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
);
|
|
}
|
|
|
|
void _updateSelectedDate() {
|
|
final daysInMonth = DateTime(_selectedYear, _selectedMonth + 1, 0).day;
|
|
_selectedDay = _selectedDay.clamp(1, daysInMonth);
|
|
_selectedDate = DateTime(_selectedYear, _selectedMonth, _selectedDay);
|
|
}
|
|
|
|
Widget _buildActionButtons() {
|
|
return ButtonBar(
|
|
children: <Widget>[
|
|
TextButton(
|
|
child: Text('キャンセル'),
|
|
onPressed: () => Navigator.of(context).pop(),
|
|
),
|
|
TextButton(
|
|
child: Text('OK'),
|
|
onPressed: () => Navigator.of(context).pop(_selectedDate),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_yearScrollController.dispose();
|
|
_monthScrollController.dispose();
|
|
_dayScrollController.dispose();
|
|
super.dispose();
|
|
}
|
|
}
|