大幅変更&環境バージョンアップ
This commit is contained in:
271
lib/widgets/custom_date_picker.dart
Normal file
271
lib/widgets/custom_date_picker.dart
Normal file
@ -0,0 +1,271 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user