パッケージ、リポジトリ、アプリカテゴリを検索

m_calendar のカバー
パッケージ詳細v1.5.1

m_calendar

日付およびリストベースの選択をサポートし、ユーザー定義の装飾が可能なカスタマイズ可能で軽量なFlutterカレンダーウィジェットパッケージです。

AndroidiOSWebmacOSWindowsLinux
30日間ダウンロード
226
いいね数
12
Pub ポイント
160

パッケージをインストール

flutter pub add m_calendar

パッケージ概要

公開情報に基づく選定ガイドです。参考としてご利用ください。

m_calendar は、カレンダーウィジェットを構築するための軽量で高度にカスタマイズ可能な Flutter パッケージです。日付ベースおよびリストベースの選択モードをサポートしており、ユーザーが日付を選択したり、構造化されたリストでイベントを表示したりできます。開発者は、色、アイコン、バッジなどのカスタム装飾を日付に適用して、特定の日を強調表示できます。このパッケージは、Android、iOS、Web、macOS、Windows、Linux を含むすべての主要プラットフォームでシンプルさとパフォーマンスを重視して設計されています。直感的な日付選択と視覚的カスタマイズが必要なアプリに最適です。

用途

  • スケジューリングアプリの日付ピッカー
  • ハイライト付き日付でのイベント計画
  • ユーザーの誕生日または記念日トラッキング
  • 生産性ツールにおけるカレンダービュー
  • カスタム日付選択インターフェース

主な機能

  • 日付およびリスト選択モードをサポートしています
  • 拡張可能な日付装飾システム
  • 軽量でパフォーマンスに優れる
  • クロスプラットフォーム互換性
  • Flutter UI との簡単な統合
  • カスタマイズ可能な外観と動作

適している対象

  • カレンダーフィーチャーを開発する開発者
  • 視覚フィードバック付きの日付選択を必要とするアプリ
  • 最小限の依存関係を必要とするプロジェクト
  • クロスプラットフォーム用カレンダーコンポーネント
  • 柔軟な日付スタイルを望むUIデザイナー

注意事項

  • 限定された組み込みイベント管理
  • ネイティブな繰り返しイベントのサポートなし
  • 日付ロジックの手動処理が必要です
  • シンプルから中程度の複雑さのカレンダーに最適
  • 高度なスケジューリングを備えた機能豊富なカレンダーアプリには適していない

元の README

関連するソースリポジトリの README 原文のスナップショットです。最新の内容はリポジトリをご覧ください。

📆 m_calendar

A customizable, lightweight Flutter calendar package with monthly, weekly, and horizontal layouts, single/range date selection, marked dates, and a built-in month/year picker.

pub.dev license


🖼️ Previews

Monthly range selection Monthly single selection Weekly calendar

Horizontal calendar

✨ Features

Feature Monthly Weekly Horizontal
Single-date selection ✅ ✅ ✅
Range selection ✅ — —
Marked dates ✅ — ✅
Month/year picker ✅ — ✅
Custom cell decoration ✅ ✅ ✅
Custom cell widget ✅ ✅ ✅
Auto-scroll to date — — ✅

📝 Behavioral notes

  • Monthly and weekly views start the week on Saturday by default. Pass startDay (e.g. Day.monday) to change it.
  • The weekly view reports a single picked date per tap (the first day of the selected week). The isRangeSelection flag is accepted for API symmetry, but weekly range selection is not implemented yet.
  • The horizontal view is always single-select, and selectedDay is initialized to today before any interaction — so controller.selectedDates returns [today] until the user (or controller) picks another date.
  • A cross-month range set via controller.selectRange(start, end) is truncated to the end of the start month.
  • Attach one MCalendarController per MCalendar widget. Attaching the same controller to multiple calendars is not supported.

🚀 Installation

Add to your pubspec.yaml:

dependencies:
  m_calendar: ^1.4.0

Then run:

flutter pub get

Import in your Dart file:

import 'package:m_calendar/m_calendar.dart';

📖 Usage

Monthly calendar (default)
MCalendar(
  selectedMonth: DateTime.now(),
  onUserPicked: (List<DateTime> dates) {
    // Single selection → list contains one date.
    print(dates);
  },
)
Monthly calendar with range selection
MCalendar(
  selectedMonth: DateTime.now(),
  isRangeSelection: true,
  onUserPicked: (List<DateTime> dates) {
    // Range → list contains every date in the selected range.
    // The callback fires only once both range endpoints are picked.
    print('From ${dates.first} to ${dates.last}');
  },
)
Monthly calendar with marked dates
MCalendar(
  selectedMonth: DateTime.now(),
  markedDaysList: [
    MarkedDaysModel(
      selectedDateList: [
        DateTime(2025, 6, 10),
        DateTime(2025, 6, 15),
      ],
      decoration: BoxDecoration(
        color: Colors.blue.withOpacity(0.3),
        shape: BoxShape.circle,
      ),
    ),
  ],
  onUserPicked: (dates) => print(dates),
)
Monthly calendar with month/year picker
MCalendar(
  selectedMonth: DateTime.now(),
  showMonthYearPicker: true, // tap the header to open the picker
  onUserPicked: (dates) => print(dates),
)

Note: MCalendar.monthly(...) defaults showMonthYearPicker to true.
The MCalendar(...) shorthand defaults it to false. Explicitly set it to your preference.

Programmatic control with MCalendarController

Control navigation and programmatic selections from outside the calendar:

final controller = MCalendarController();

MCalendar(
  controller: controller,
  selectedMonth: DateTime(2026, 3),
  onUserPicked: (dates) => print(dates),
)

// Imperative controls:
controller.nextMonth();
controller.previousMonth();
controller.setMonth(DateTime(2026, 6));
controller.selectDate(DateTime(2026, 6, 15));
controller.selectRange(DateTime(2026, 6, 10), DateTime(2026, 6, 18));
controller.clearSelection();

// Query selection:
print(controller.selectedDates);
Custom day cell builder (dayBuilder)

Render custom widgets with event dots, badges, or icons inside day cells:

MCalendar(
  selectedMonth: DateTime.now(),
  dayBuilder: (context, date, state) {
    if (state.isDisabled) {
      return Center(child: Text('${date.day}', style: const TextStyle(color: Colors.grey)));
    }
    if (state.isToday) {
      return Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Text('${date.day}', style: const TextStyle(fontWeight: FontWeight.bold)),
          const Icon(Icons.circle, size: 4, color: Colors.blue),
        ],
      );
    }
    return null; // return null to fall back to default rendering
  },
  onUserPicked: (dates) => print(dates),
)
Disabling dates (minDate, maxDate, isDateDisabled)

Prevent selection of past dates, weekends, or specific days:

MCalendar(
  selectedMonth: DateTime.now(),
  minDate: DateTime.now(), // past dates disabled
  maxDate: DateTime.now().add(const Duration(days: 60)), // max 60 days ahead
  isDateDisabled: (date) => date.weekday == DateTime.sunday, // disable Sundays
  disabledDecoration: BoxDecoration(
    color: Colors.grey.shade200,
    borderRadius: BorderRadius.circular(6),
  ),
  onUserPicked: (dates) => print(dates),
)
Animations (opt-in)

Animations are off by default to keep existing behavior unchanged. Pass a [CalendarAnimations] configuration to any calendar to enable them:

MCalendar(
  selectedMonth: DateTime.now(),
  animations: const CalendarAnimations(), // opt in
  onUserPicked: (dates) => print(dates),
)

This animates:

  • selection / range highlight changes on monthly, weekly, and horizontal cells, plus the month-picker tiles,
  • a fade + directional slide when the displayed month changes,
  • a smooth grid resize between months with different row counts.

Tune the timings and curves, or disable specific parts:

const CalendarAnimations(
  selectionDuration: Duration(milliseconds: 150),
  monthTransitionDuration: Duration(milliseconds: 250),
  sizeDuration: Duration.zero, // keep the height change instant
)

MCalendar(
  selectedMonth: DateTime.now(),
  animations: CalendarAnimations.none, // explicitly disable
  onUserPicked: (dates) => print(dates),
)

Animations automatically become instant when the platform requests reduced motion (MediaQueryData.disableAnimations).


Weekly calendar
MCalendar.weekly(
  selectedMonth: DateTime.now(),
  startDay: Day.sunday, // first day of the week; defaults to Day.saturday
  onUserPicked: (List<DateTime> dates) {
    // Returns [firstDayOfSelectedWeek].
    print(dates);
  },
)

The weekly view shows a scrollable table with one row per month (last 6 months) and up to 6 week columns. Months that span 6 calendar weeks (e.g. September 2023 with a Saturday week start) are displayed correctly without data loss.


Horizontal calendar
// Wrap in a SizedBox or Expanded to give the view a bounded height.
SizedBox(
  width: double.infinity,
  height: 120,
  child: MCalendar.horizontal(
    selectedMonth: DateTime.now(),
    onUserPicked: (DateTime date) {
      // Always a single date.
      print(date);
    },
  ),
)

The horizontal view callback is void Function(DateTime) — not a List — because the horizontal view only supports single-date selection.

Horizontal calendar with date range and auto-scroll
SizedBox(
  width: double.infinity,
  height: 120,
  child: MCalendar.horizontal(
    selectedMonth: DateTime.now(),
    initialDate: DateTime.now(),                       // scroll-to target
    endDate: DateTime.now().add(const Duration(days: 30)), // last selectable day
    autoScroll: true,                                  // default: true
    onUserPicked: (date) => print(date),
  ),
)

initialDate is also the first selectable date. Dates before initialDate and after endDate are shown greyed-out and cannot be tapped.

Assertion: passing initialDate after endDate throws an assertion error in debug mode with a clear message.


🎨 Styling

Cell decoration & child
MCalendar(
  selectedMonth: DateTime.now(),
  // Default (unselected) cell decoration
  decoration: BoxDecoration(
    color: Colors.grey.shade100,
    borderRadius: BorderRadius.circular(8),
  ),
  // Selected cell decoration
  userPickedDecoration: BoxDecoration(
    color: Colors.teal,
    borderRadius: BorderRadius.circular(8),
  ),
  // Custom widget inside the selected cell (overrides the default day number)
  userPickedChild: const Icon(Icons.check, color: Colors.white),
  // Cell padding
  cellPadding: const EdgeInsets.all(8),
  onUserPicked: (dates) => print(dates),
)
Header & week-label styling
MCalendar(
  selectedMonth: DateTime.now(),
  showMonthYearPicker: true,
  // Header text (month + year label)
  weekNameHeaderStyle: const TextStyle(
    fontWeight: FontWeight.bold,
    color: Colors.indigo,
  ),
  onUserPicked: (dates) => print(dates),
)
Month/year picker customization (horizontal view example)
MCalendar.horizontal(
  selectedMonth: DateTime.now(),
  showMonthYearPicker: true,
  monthYearPickerSelectedMonthColor: Colors.teal,
  monthYearPickerUnselectedMonthColor: Colors.grey.shade200,
  monthYearPickerCrossAxisCount: 4,
  monthYearPickerChildAspectRatio: 2.0,
  onUserPicked: (date) => print(date),
)

📦 Public API

MCalendar (monthly, default)
Parameter Type Default Description
selectedMonth DateTime required Month to display. Day/time components are ignored.
onUserPicked void Function(List<DateTime>) required Fires with selected dates.
isRangeSelection bool false Enables range selection.
showMonthYearPicker bool false Shows the month/year picker header.
markedDaysList List<MarkedDaysModel>? null Dates to visually mark.
decoration BoxDecoration? null Default cell decoration.
userPickedDecoration BoxDecoration? null Selected-cell decoration.
userPickedChild Widget? null Widget inside the selected cell.
defaultChild Widget? null Widget inside unselected cells.
cellPadding EdgeInsets? null Padding inside each cell.
controller MCalendarController? null Controller for programmatic navigation and selection.
dayBuilder CalendarDayBuilder? null Custom widget builder for day cells.
minDate DateTime? null Earliest selectable date.
maxDate DateTime? null Latest selectable date.
isDateDisabled bool Function(DateTime)? null Predicate to disable specific dates.
disabledDecoration BoxDecoration? null Decoration for disabled day cells.
disabledTextStyle TextStyle? null Text style for disabled day cell numbers.
startDay Day Day.saturday First day of the week; changes cell alignment and header labels.
animations CalendarAnimations? null Opt-in animation config; null = instant updates.
MCalendar.weekly

Same as above plus:

Parameter Type Default Description
startDay Day Day.saturday First day of the week.
MCalendar.horizontal
Parameter Type Default Description
selectedMonth DateTime required Month to display.
onUserPicked void Function(DateTime) required Fires with selected date.
initialDate DateTime? null First selectable date; auto-scroll target.
endDate DateTime? null Last selectable date.
autoScroll bool true Scroll to initialDate on first build.
showMonthYearPicker bool false Shows the month/year picker header.
showWeekDays bool true Show weekday labels under dates.
markedDaysList List<MarkedDaysModel>? null Dates to visually mark.
decoration BoxDecoration? null Default cell decoration.
userPickedDecoration BoxDecoration? null Selected-cell decoration.
headerHeight double? 320 Height of the picker bottom sheet.
headerIconColor Color? null Color for header arrow icons.
headerTextStyle TextStyle? null Style for header month/year text.
dateTextStyle TextStyle? null Style for the day number.
weekDaysTextStyle TextStyle? null Style for the weekday label.
selectedDateTextStyle TextStyle? null Day number style when selected.
selectedWeekDaysTextStyle TextStyle? null Weekday label style when selected.
animations CalendarAnimations? null Opt-in animation config; null = instant updates.
MarkedDaysModel
MarkedDaysModel(
  selectedDateList: [DateTime(2025, 6, 10)],
  decoration: BoxDecoration(color: Colors.amber, shape: BoxShape.circle),
  child: const Icon(Icons.star, size: 12), // optional overlay widget
)
Day enum

Used for MCalendar.weekly(startDay: ...):

Day.monday  Day.tuesday  Day.wednesday  Day.thursday
Day.friday  Day.saturday  Day.sunday
CalendarAnimations
Field Default Description
selectionDuration 180ms Duration of selection/range highlight transitions.
selectionCurve Curves.easeOut Curve for selection transitions.
monthTransitionDuration 250ms Duration of the month-change fade + slide.
monthTransitionCurve Curves.easeOutCubic Curve for the month-change transition.
sizeDuration 200ms Duration of grid resizes between row counts.

CalendarAnimations.none disables all of them. Any duration is forced to Duration.zero when the platform requests reduced motion.


⚠️ Migration Guide

1.3.x → 1.4.0

No breaking changes. All existing code continues to work.

Typo fix — provider class names (non-breaking, additive)

The internal providers were misspelled. The corrected names are now exported:

Old name (deprecated) New name
MonthlyCalenderTableProvider MonthlyCalendarTableProvider
WeeklyCalenderTableProvider WeeklyCalendarTableProvider

The old names still compile (they are @Deprecated typedef aliases) but will be removed in a future major release. Migrate by renaming:

// Before
MonthlyCalenderTableProvider()

// After
MonthlyCalendarTableProvider()
Barrel exports (non-breaking, additive)

MarkedDaysModel and Day are now re-exported from m_calendar.dart. You can remove separate imports if you had them:

// Before
import 'package:m_calendar/m_calendar.dart';
import 'package:m_calendar/model/marked_date_model.dart';
import 'package:m_calendar/provider/weekly_calendar_table_provider.dart';

// After
import 'package:m_calendar/m_calendar.dart'; // MarkedDaysModel and Day included

🔍 Frequently Asked Questions

Q: Why does the range callback fire only when both endpoints are selected?
A: The callback fires once the range is complete (two taps). During the first tap, rangeStart is set internally; the callback fires on the second tap with the full sorted date list.

Q: What happens if I tap the same date twice in range mode?
A: A single-date range is returned: [date].

Q: What happens if I tap a third date after completing a range?
A: The old range is cleared and a new range starts from the third tap.

Q: Can I use DateTime values with time components for markedDaysList?
A: Yes. Date matching always ignores the time component — only year, month, and day are compared.

Q: Can I show more than one decoration model on the same date?
A: The first matching MarkedDaysModel wins. Ensure no two models share the same date if you want distinct decorations.

Q: Why does MCalendar.weekly show up to 6 week columns?
A: Depending on startDay, some months span 6 calendar weeks (e.g. September 2023 with a Saturday start). Previous versions silently dropped the 6th week; 1.4.0 renders it correctly.


📄 License

MIT © Muntasir Asif

カテゴリー

依存関係

依存関係一覧 2 件

ソースリポジトリ

このパッケージを使用しているプロジェクト

データはまだありません。