OBCalendaris a SwiftUI-based calendar library designed to allow you to easily create your own custom calendars. With this structure, you can customize the days, months, and years.- To change the locale of calendar-related texts, create a
Calendarobject, set its locale, and pass it to the OBCalendar initializer. - To configure the date range, pass
startDateanddrawingRangeto theOBCalendar's initializer.
- You can visit for the documentation
- You can visit for the tutorial step by step
- Video tutorial:
- iOS 14+
- Swift 5.10+
-
Open your Xcode project.
-
Go to File > Add Packages.
-
In the search bar, enter the following URL :
https://github.com/oBilet/OBCalendar.git -
Choose the package version or branch and click Add Package.
-
You can create
OBCalendarspecifyingstartDate(default is: current date) and DrawingRange (day, month or year from startDate) (defaultdrawingRangeis.year(1)). -
Modifiers are optional and you can choose to use
baseViewor use the packed views (daysView, monthsView) inside the modifiers or you can return your custom view. -
The dayModifier's "viewModel" contains
CalendarModel.Year,CalendarModel.MonthandCalendarModel.Dayand a view is created for each day using these models. -
Modifiers should be written in this order: dayModifier -> monthModifier -> yearModifier
-
baseViewin the modifier closures is the default view that has its own custom modification over the previous modifier method's return type, like having a header in months for example. -
daysViewin the monthModifier andmonthsViewin the yearModifier are the untouched pack of views that will have the modifications from previous modifiers. -
Every modifier has its own viewModel in the closure parameter list. Default name is "viewModel" and it contains some functions and related models:
CalendarModel.Year,CalendarModel.MonthandCalendarModel.Day. -
The data models which the closures' related viewModels contain are:
Day+Month+Yearfor dayModifier,Month+Yearfor month modifier and onlyYearfor yearModifier. -
You can fully customize the view for each day, month, and year by calling
dayModifier,monthModifierandyearModifiermodifier functions each of which acceptsViewBuilderblocks. -
This structure facilitates efficient and adaptable development.
-
If you'd like to create the calendar from scratch, you can use the base version of it as well. You can customize it even further by setting start and end dates to generating and providing your own date array for custom layouts.
To integrate OBCalendar into your project using Swift Package Manager, follow these steps:
For better performance, use lazyDays: true and lazyMonths: true.
If you are using programmatic scroll, set lazyYears: false because subviews need to be loaded into memory once for ScrollViewProxy to recognize their id values.
Default:
// 1 year of drawing range
OBCalendar(drawingRange: .year(1))
// 3 months of drawing range
OBCalendar(drawingRange: .month(3))
// 60 days of drawing range
OBCalendar(drawingRange: .day(60))Range selection example:
OBCalendar()
.dayModifier { baseView, viewModel in
baseView
.selectable(
lhsDate: $firstSelectedDate,
rhsDate: $secondSelectedDate,
viewModel: viewModel
)
}Horizontal Scroll:
GeometryReader { geometry in
OBCalendar(
monthScrollAxis: .horizontal,
yearScrollAxis: .horizontal
)
.monthModifier { baseView, daysView, viewModel in
baseView
.padding()
.frame(width: geometry.size.width)
}
}DayModifier:
OBCalendar()
.dayModifier { baseView, viewModel in
baseView
.background(Color.blue)
.padding(2)
.foregroundColor(.white)
}MonthModifier:
OBCalendar()
.monthModifier{ baseView, daysView, viewModel in
VStack {
Text("Modified Months")
Text(viewModel.title)
daysView
}
.padding()
}Modified Day + Modified Month:
OBCalendar()
.dayModifier { baseView, viewModel in
baseView
.foregroundColor(Color(.red))
}
.monthModifier { baseView, daysView, viewModel in
VStack {
Text("Modified Months")
daysView
}
.padding()
}BaseCalendar
let today = Date()
let twoYearsLater = calendar.date(byAdding: .year, value: 2, to: today)!
OBBaseCalendar(startDate: today, endDate: twoYearsLater) { model, scrollProxy in
// day view goes here
let day = model.day
Text("\(day.day)")
} monthContent: { model, scrollProxy, daysView in
// month view goes here
daysView
} yearContent: { model, scrollProxy, monthsView in
// year view goes here
monthsView
}BaseCalendar + Custom layouts
//Implement your own layout
let years = [CalendarModel.Year]()
// Or use default layout
let defaultLayout = CalendarModelBuilder.defaultLayout(
calendar: .current,
startDate: Date(),
endDate: Date().addingTimeInterval(3600 * 24 * 365)
)
OBBaseCalendar(years: years) { model, scrollProxy in
// day view goes here
let day = model.day
Text("\(day.day)")
} monthContent: { model, scrollProxy, daysView in
// month view goes here
daysView
} yearContent: { model, scrollProxy, monthsView in
// year view goes here
monthsView
}Feel free to explore the SwiftUI-powered flexibility of OBCalendar to meet your custom calendar needs!