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 { 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: [ 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: [ 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(); } }