You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中日期范围选择器(DateRange Picker)的设计实现方法

在Flutter中实现日期范围选择器的几种方法

1. 使用Flutter官方原生组件showDateRangePicker

Flutter SDK自带日期范围选择弹窗,无需额外依赖,适合快速实现基础需求。

示例代码:

import 'package:flutter/material.dart';

class DateRangePickerDemo extends StatefulWidget {
  const DateRangePickerDemo({super.key});

  @override
  State<DateRangePickerDemo> createState() => _DateRangePickerDemoState();
}

class _DateRangePickerDemoState extends State<DateRangePickerDemo> {
  DateTimeRange? _selectedDateRange;

  Future<void> _showDateRangePicker() async {
    final picked = await showDateRangePicker(
      context: context,
      firstDate: DateTime(2020),
      lastDate: DateTime(2025),
      initialDateRange: _selectedDateRange,
      builder: (context, child) {
        return Theme(
          data: ThemeData.light().copyWith(
            colorScheme: const ColorScheme.light(
              primary: Colors.blue, // 选中日期的主题色
              onPrimary: Colors.white,
              surface: Colors.white,
              onSurface: Colors.black,
            ),
            dialogBackgroundColor: Colors.white,
          ),
          child: child!,
        );
      },
    );

    if (picked != null) {
      setState(() {
        _selectedDateRange = picked;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('日期范围选择器')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(_selectedDateRange == null
                ? '未选择日期范围'
                : '选中范围: ${_selectedDateRange!.start.toString().split(' ')[0]} 至 ${_selectedDateRange!.end.toString().split(' ')[0]}'),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: _showDateRangePicker,
              child: const Text('选择日期范围'),
            ),
          ],
        ),
      ),
    );
  }
}

2. 自定义日期范围选择器(适配参考样式)

如果需要更贴合参考图的嵌入式双日期选择UI,可以手动组合组件实现:

示例代码:

import 'package:flutter/material.dart';

class CustomDateRangePicker extends StatefulWidget {
  const CustomDateRangePicker({super.key});

  @override
  State<CustomDateRangePicker> createState() => _CustomDateRangePickerState();
}

class _CustomDateRangePickerState extends State<CustomDateRangePicker> {
  DateTime? _startDate;
  DateTime? _endDate;

  Future<void> _pickDate(bool isStart) async {
    final picked = await showDatePicker(
      context: context,
      initialDate: isStart ? (_startDate ?? DateTime.now()) : (_endDate ?? DateTime.now()),
      firstDate: DateTime(2020),
      lastDate: DateTime(2025),
    );

    if (picked != null) {
      setState(() {
        if (isStart) {
          _startDate = picked;
          // 自动修正结束日期不早于开始日期
          if (_endDate != null && _endDate!.isBefore(picked)) {
            _endDate = picked;
          }
        } else {
          _endDate = picked;
        }
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 20),
      child: Row(
        children: [
          Expanded(
            child: GestureDetector(
              onTap: () => _pickDate(true),
              child: Container(
                padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 14),
                decoration: BoxDecoration(
                  border: Border.all(color: Colors.grey.shade300),
                  borderRadius: BorderRadius.circular(8),
                ),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const Text('开始日期', style: TextStyle(fontSize: 12, color: Colors.grey)),
                    const SizedBox(height: 4),
                    Text(
                      _startDate == null ? '选择日期' : _startDate!.toString().split(' ')[0],
                      style: const TextStyle(fontSize: 16),
                    ),
                  ],
                ),
              ),
            ),
          ),
          const SizedBox(width: 16),
          const Text('至', style: TextStyle(fontSize: 16)),
          const SizedBox(width: 16),
          Expanded(
            child: GestureDetector(
              onTap: () => _pickDate(false),
              child: Container(
                padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 14),
                decoration: BoxDecoration(
                  border: Border.all(color: Colors.grey.shade300),
                  borderRadius: BorderRadius.circular(8),
                ),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const Text('结束日期', style: TextStyle(fontSize: 12, color: Colors.grey)),
                    const SizedBox(height: 4),
                    Text(
                      _endDate == null ? '选择日期' : _endDate!.toString().split(' ')[0],
                      style: const TextStyle(fontSize: 16),
                    ),
                  ],
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

3. 使用第三方包flutter_date_pickers

如果需要更丰富的样式(如周/月选择、自定义高亮),可以使用flutter_date_pickers包,UI风格更贴近商用产品。

步骤1:添加依赖

在pubspec.yaml中加入:

dependencies:
  flutter_date_pickers: ^2.0.0

步骤2:实现代码

import 'package:flutter/material.dart';
import 'package:flutter_date_pickers/flutter_date_pickers.dart' as pickers;

class ThirdPartyDateRangePicker extends StatefulWidget {
  const ThirdPartyDateRangePicker({super.key});

  @override
  State<ThirdPartyDateRangePicker> createState() => _ThirdPartyDateRangePickerState();
}

class _ThirdPartyDateRangePickerState extends State<ThirdPartyDateRangePicker> {
  DateTimeRange? _selectedRange;
  final DateTime _firstDate = DateTime(2020);
  final DateTime _lastDate = DateTime(2025);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('第三方日期范围选择器')),
      body: Column(
        children: [
          pickers.DateRangePicker(
            selectedDateRange: _selectedRange,
            onChanged: (range) => setState(() => _selectedRange = range),
            firstDate: _firstDate,
            lastDate: _lastDate,
            datePickerStyles: const pickers.DatePickerStyles(
              selectedDateStyle: TextStyle(color: Colors.white),
              selectedSingleDateDecoration: BoxDecoration(
                color: Colors.blue,
                borderRadius: BorderRadius.all(Radius.circular(8)),
              ),
            ),
          ),
          const SizedBox(height: 20),
          Text(_selectedRange == null
              ? '未选择范围'
              : '选中: ${_selectedRange!.start.toString().split(' ')[0]} 至 ${_selectedRange!.end.toString().split(' ')[0]}'),
        ],
      ),
    );
  }
}

注意事项:

  • 使用第三方包时,建议查看最新版本文档,避免版本兼容问题。
  • 自定义样式可通过Theme或组件自带参数调整颜色、字体,匹配App设计风格。

内容的提问来源于stack exchange,提问作者Himani Upadhyay

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 05:25:19