Fastis is a fully customisable UI component for picking dates and ranges created using the JTAppleCalendar library.
- iOS 13.0+
- Xcode 11.0+
- Swift 5.0+
- Flexible customization
- Shortcuts for dates and ranges
- Single date and date range modes
CocoaPods is a dependency manager for Cocoa projects. You can install it with the following command:
$ gem install cocoapods
To integrate Fastis into your Xcode project using CocoaPods, specify it in your Podfile
:
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '13.0'
use_frameworks!
target '<Your Target Name>' do
pod 'Fastis', '~> 2.0'
end
Then, run the following command:
$ pod install
The Swift Package Manager is a tool for automating the distribution of Swift code and is integrated into the swift
compiler.
Once you have your Swift package set up, adding Fastis as a dependency is as easy as adding it to the dependencies
value of your Package.swift
.
dependencies: [
.package(url: "https://github.com/simla-tech/Fastis.git", .upToNextMajor(from: "2.0.0"))
]
Carthage isn't supported.
If you prefer not to use either of the dependency managers mentioned above, you can manually integrate Fastis into your project.
import Fastis
class MyViewController: UIViewController {
func chooseDate() {
let fastisController = FastisController(mode: .range)
fastisController.title = "Choose range"
fastisController.maximumDate = Date()
fastisController.allowToChooseNilDate = true
fastisController.shortcuts = [.today, .lastWeek]
fastisController.dismissHandler = { [weak self] action in
switch action {
case .done(let newValue):
...
case .cancel:
...
}
}
fastisController.present(above: self)
}
}
If you want to get a single date, you have to use the Date
type:
let fastisController = FastisController(mode: .single)
fastisController.initialValue = Date()
fastisController.dismissHandler = { [weak self] action in
switch action {
case .done(let resultDate):
print(resultDate) // resultDate is Date
case .cancel:
...
}
}
If you want to get a date range, you have to use the FastisRange
type:
let fastisController = FastisController(mode: .range)
fastisController.initialValue = FastisRange(from: Date(), to: Date()) // or .from(Date(), to: Date())
fastisController.dismissHandler = { [weak self] action in
switch action {
case .done(let resultRange):
print(resultRange) // resultRange is FastisRange
case .cancel:
...
}
}
FastisController has the following default configuration parameters:
var shortcuts: [FastisShortcut<Value>] = []
var allowsToChooseNilDate: Bool = false
var dismissHandler: ((DismissAction) -> Void)? = nil
var initialValue: Value? = nil
var minimumDate: Date? = nil
var maximumDate: Date? = nil
var selectMonthOnHeaderTap: Bool = true
var allowDateRangeChanges: Bool = true
var closeOnSelectionImmediately: Bool = false
shortcuts
- Shortcuts array. The default value is[]
. See Shortcuts sectionallowsToChooseNilDate
- Allow to choosenil
date. If you settrue
, the done button will always be enabled and you will be able to reset selection by you tapping on selected date again. The default value isfalse
.dismissHandler
- The block to execute after the dismissal finishes. The default value isnil
. Return DismissAction.done(FastisValue?) after the "Done" button will be tapped or DismissAction.cancel when controller dismissed without tapped the "Done" button.initialValue
- And initial value which will be selected by default. The default value isnil
.minimumDate
- Minimal selection date. Dates less than current will be marked as unavailable. The default value isnil
.maximumDate
- Maximum selection date. Dates more significant than current will be marked as unavailable. The default value isnil
.selectMonthOnHeaderTap
(Only for.range
mode) - Set this variable totrue
if you want to allow select date ranges by tapping on months. The default value istrue
.allowDateRangeChanges
(Only for.range
mode) - Set this variable tofalse
if you want to disable date range changes. Next tap after selecting a range will start a new range selection. The default value istrue
.closeOnSelectionImmediately
(Only for.single
mode) - Set this variable totrue
if you want to hide view of the selected date and close the controller right after the date is selected. The default value isfalse
Using shortcuts allows you to select set dates or date ranges quickly.
By default .shortcuts
is empty. The bottom container will be hidden if you don't provide any shortcuts.
In Fastis available some prepared shortcuts for each mode:
- For
.single
:.today
,.tomorrow
,.yesterday
- For
.range
:.today
,.lastWeek
,.lastMonth
Also, you can create your own shortcut:
var customShortcut = FastisShortcut(name: "Today") {
let now = Date()
return FastisRange(from: now.startOfDay(), to: now.endOfDay())
}
fastisController.shortcuts = [customShortcut, .lastWeek]
Fastis can be customised global or local. FastisConfig
have some sections:
calendar
- Base calendar that used to render UI. Default value is.current
controller
- base view controller (cancelButtonTitle
,doneButtonTitle
, etc.)monthHeader
- month titlesdayCell
- day cells (selection parameters, font, etc.)todayCell
- today cell (selection parameters, font, circle view, etc.). If you settodayCell
tonil
, view will usedayCell
insteadweekView
- top header view with weekday namescurrentValueView
- current value view appearance (clear button, date format, etc.)shortcutContainerView
- bottom view with shortcutsshortcutItemView
- shortcut item in the bottom view
To customise all Fastis controllers in your app, use FastisConfig.default
:
FastisConfig.default.monthHeader.labelColor = .red
To customise a special FastisController instance:
var customConfig = FastisConfig.default
customConfig.controller.dayCell.dateLabelColor = .blue
let fastisController = FastisController(mode: .range, config: customConfig)
To customise a special FastisController instance with custom calendar:
var customConfig: FastisConfig = .default
var calendar = Calendar(identifier: .islamicUmmAlQura)
calendar.locale = .autoupdatingCurrent
customConfig.calendar = calendar
let fastisController = FastisController(mode: .range, config: customConfig)
fastisController.minimumDate = calendar.date(byAdding: .month, value: -2, to: Date())
fastisController.maximumDate = calendar.date(byAdding: .month, value: 3, to: Date())
To customise a today cell:
let config = FastisConfig.withCurrentDate
config.todayCell.dateLabelColor = .red
config.todayCell.onRangeLabelColor = .red
config.todayCell.circleSize = 4
config.todayCell.circleViewColor = .red
If you don't want to customzie today date cell, just set config.todayCell = nil
and today cell will use dayCell
config.
The library also contains a SwiftUI wrapper
If you want to get a date range:
FastisView(mode: .single, dismissHandler: { action in
switch action {
case .done(let resultDate):
print(resultDate) // resultDate is Date
case .cancel:
...
}
})
.title("Choose range")
.initialValue(self.currentValue as? FastisRange)
.minimumDate(Calendar.current.date(byAdding: .month, value: -2, to: Date()))
.maximumDate(Calendar.current.date(byAdding: .month, value: 3, to: Date()))
.allowToChooseNilDate(true)
.allowDateRangeChanges(false)
.shortcuts([.lastWeek, .lastMonth])
.selectMonthOnHeaderTap(true)
If you want to get a single date:
FastisView(mode: .range, dismissHandler: { action in
switch action {
case .done(let resultRange):
print(resultRange) // resultRange is FastisRange
case .cancel:
...
}
})
.title("Choose date")
.initialValue(self.currentValue as? Date)
.minimumDate(Calendar.current.date(byAdding: .month, value: -2, to: Date()))
.maximumDate(Date())
.allowToChooseNilDate(true)
.allowDateRangeChanges(false)
.shortcuts([.yesterday, .today, .tomorrow])
.closeOnSelectionImmediately(true)
- Ilya Kharlamov (@ilia3546)
- Uriy Devyataev (@UriyDevyataev)
Fastis is released under the MIT license. See LICENSE for details.