Skip to content

mark-x64/MBExpandableCalendar

Repository files navigation

MBExpandableCalendar

简体中文

Swift 6.0 iOS 18+ SPM compatible MIT License

A pure-SwiftUI calendar component that collapses smoothly between month view and week view via drag gesture, with horizontal month paging and per-date badge support.

Screenshots

Screenshots Description
Month View — Full month grid with per-date badge counts. Adapts to 4–6 row months. Light and dark mode.
Week View (Collapsed) — Collapses to a single-week strip via drag gesture. Spring-animated with rubber-band overscroll feel.
Variable Row Count — 4-row vs 6-row months. Calendar height animates smoothly as months change.
Content Styling — The content area below the calendar is fully composable. Left: flat edge-to-edge. Right: rounded card.
Custom Content — Any SwiftUI view works as the scrollable content area beneath the calendar.

Features

  • Month ↔ Week collapse — drag-driven, spring-animated transition between full month grid and single-week strip
  • Horizontal month paging — swipe left/right to navigate months with crossfade transition
  • Badge counts — per-date badge overlay (top-right corner), driven by a (Date) -> Int closure
  • Rubber-band overscroll — elastic feel when dragging past collapse bounds
  • Scroll-linked gesture — collapse only activates when the content scroll view is at the top
  • Zero dependencies — pure SwiftUI, no external packages

Requirements

  • iOS 18.0+
  • Swift 6.0+
  • Xcode 16.0+

Why iOS 18? The month paging strip in CompactCalendarView is built on the SwiftUI scroll enhancements introduced in iOS 18: scrollPosition(id:), scrollTargetBehavior(.paging), scrollTransition(.interactive, ...), onScrollGeometryChange, and containerRelativeFrame. These APIs are not available on iOS 17.

Installation

Swift Package Manager

Add the package in Xcode via File → Add Package Dependencies, or in Package.swift:

dependencies: [
    .package(url: "https://github.com/mark-x64/MBExpandableCalendar", from: "1.0.0")
]

Then add the target:

.target(
    name: "YourApp",
    dependencies: [
        .product(name: "MBExpandableCalendar", package: "MBExpandableCalendar")
    ]
)

Usage

ExpandableCalendarContainer (recommended)

The full-featured container: calendar header on top, your scrollable content below, with built-in collapse gesture coordination.

import MBExpandableCalendar

struct CalendarScreen: View {
    @State private var selectedDate = Date()

    var body: some View {
        ExpandableCalendarContainer(
            selectedDate: $selectedDate,
            badgeCount: { date in
                Calendar.current.isDateInToday(date) ? 3 : 0
            }
        ) { selectedDate in
            VStack(alignment: .leading, spacing: 12) {
                Text("Selected: \(selectedDate, format: .dateTime.month().day())")
            }
            .padding()
        }
    }
}

The container owns the outer scroll view and collapse coordination. Provide normal SwiftUI content for the selected date.

CompactCalendarView (standalone)

Use the calendar grid on its own when you need custom gesture handling or a non-standard layout:

import MBExpandableCalendar

CompactCalendarView(
    selectedDate: $date,
    badgeCount: { _ in 0 },
    collapse: collapseValue,           // 0 = month, 1 = week
    isDraggingVertically: isDragging,
    suppressTap: suppress
)

API

ExpandableCalendarContainer

Parameter Type Description
selectedDate Binding<Date> Currently selected date
badgeCount (Date) -> Int Badge count for each date
content (Date) -> Content Content below the calendar; receives the selected date

CompactCalendarView

Parameter Type Default Description
selectedDate Binding<Date> Currently selected date
badgeCount (Date) -> Int Badge count for each date
overscaleAnchor UnitPoint .center Anchor for rubber-band scale effect
collapse CGFloat 0 Collapse progress: 0 = month, 1 = week
isDraggingVertically Bool false Disables horizontal paging during vertical drag
suppressTap Bool false Prevents date taps during a drag gesture

License

MIT

About

A SwiftUI calendar component with smooth month ↔ week collapse, horizontal month paging with live height interpolation, badge support, and a UIKit-backed expandable drawer container.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages