Flutter DatePicker组件改造需求:将弹窗选择转为常驻日历Widget并调整时间显示样式
Got it, let's revamp your calendar widget to show a persistent full calendar and adjust the time display to match your desired UI. Here's a complete solution with explanations:
Step 1: Add Required Dependency
First, we'll use the table_calendar package for the persistent calendar view. Add this to your pubspec.yaml:
dependencies: flutter: sdk: flutter intl: ^0.18.1 table_calendar: ^3.0.9 # Use the latest version available
Run flutter pub get to install it.
Step 2: Full Modified Code
Replace your existing code with this version, which includes the persistent calendar and updated time display:
import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:table_calendar/table_calendar.dart'; class ExampleCalendar extends StatefulWidget { @override _ExampleCalendarState createState() => _ExampleCalendarState(); static Route route() { return MaterialPageRoute<void>(builder: (_) => ExampleCalendar()); } } class _ExampleCalendarState extends State<ExampleCalendar> { DateTime _selectedDate = DateTime.now(); TimeOfDay _selectedTime = TimeOfDay.now(); CalendarFormat _calendarFormat = CalendarFormat.month; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: Colors.transparent, leading: IconButton( icon: const Icon(Icons.arrow_back, color: Colors.black), onPressed: () => Navigator.of(context).pop(), ), ), body: _menuPage(context), ); } Widget _menuPage(BuildContext context) { return SafeArea( child: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _persistentCalendarAndTimePicker(context), ], ), ), ); } Widget _persistentCalendarAndTimePicker(BuildContext context) { return Padding( padding: const EdgeInsets.all(16.0), child: Column( children: [ // Persistent Full Calendar TableCalendar( firstDay: DateTime.now(), lastDay: DateTime.now().add(const Duration(days: 100000)), focusedDay: _selectedDate, calendarFormat: _calendarFormat, selectedDayPredicate: (day) => isSameDay(_selectedDate, day), onDaySelected: (selectedDay, focusedDay) { setState(() => _selectedDate = selectedDay); }, onFormatChanged: (format) { setState(() => _calendarFormat = format); }, onPageChanged: (focusedDay) => _selectedDate = focusedDay, calendarStyle: const CalendarStyle( selectedDecoration: BoxDecoration( color: Colors.lightBlueAccent, shape: BoxShape.circle, ), todayDecoration: BoxDecoration( color: Colors.grey[300], shape: BoxShape.circle, ), ), headerStyle: const HeaderStyle( formatButtonVisible: true, titleCentered: true, ), ), const SizedBox(height: 20), // Time & Date Display Bar (matches your original layout with improvements) Container( width: double.infinity, height: 100, child: Row( children: [ Expanded( child: Container( color: Colors.lightBlueAccent, child: Center( // Optional: Replace with persistent wheel picker if you don't want a dialog child: TextButton( onPressed: () => _openTimePicker(context), child: Text( _selectedTime.format(context), style: const TextStyle( fontSize: 30.0, color: Colors.black, fontWeight: FontWeight.w500, ), ), ), ), ), ), Expanded( child: Container( color: const Color.fromRGBO(7, 190, 200, 0.1), child: Center( child: Text( DateFormat('dd.MM.yyyy').format(_selectedDate), style: const TextStyle( fontSize: 28.0, color: Colors.black, fontWeight: FontWeight.w500, ), ), ), ), ), ], ), ), ], ), ); } Future<void> _openTimePicker(BuildContext context) async { final pickedTime = await showTimePicker( context: context, initialTime: _selectedTime, helpText: "Choose Time", ); if (pickedTime != null) { setState(() => _selectedTime = pickedTime); } } }
Key Changes Explained
Persistent Calendar:
- Replaced the date button with
TableCalendar, which shows a full, interactive calendar directly in your UI. - You can switch between month/week/day views using the format button in the header.
- Selected dates are highlighted, and tapping a date updates
_selectedDateinstantly.
- Replaced the date button with
Time Display & Selection:
- Kept your original color scheme and layout for the time/date bar, but updated the date to show full
dd.MM.yyyyformat (adjust this withDateFormatif you need a different style). - The time button still opens a picker dialog, but if you want a persistent wheel picker (no dialog), replace the
TextButtonwith this Cupertino-style wheel:// Replace the TextButton in the time container with this Row( mainAxisAlignment: MainAxisAlignment.center, children: [ SizedBox( width: 60, child: CupertinoPicker( itemExtent: 40, onSelectedItemChanged: (index) { setState(() => _selectedTime = _selectedTime.replacing(hour: index)); }, children: List.generate(24, (i) => Text('${i.toString().padLeft(2, '0')}')), ), ), const Text(':', style: TextStyle(fontSize: 30)), SizedBox( width: 60, child: CupertinoPicker( itemExtent: 40, onSelectedItemChanged: (index) { setState(() => _selectedTime = _selectedTime.replacing(minute: index)); }, children: List.generate(60, (i) => Text('${i.toString().padLeft(2, '0')}')), ), ), ], ) - This wheel picker stays visible in the UI, letting users adjust time without opening a dialog.
- Kept your original color scheme and layout for the time/date bar, but updated the date to show full
State Management:
- Split date and time into separate state variables (
_selectedDateand_selectedTime) for cleaner logic. - All UI updates trigger
setStateto refresh the view immediately.
- Split date and time into separate state variables (
内容的提问来源于stack exchange,提问作者azeter09
相关产品推荐
相关产品推荐

