如何 Select 范围 - Swift 中的 FSCalendar?
How to Select Range - FSCalendar in Swift?
我正在尝试在我的一个项目中使用 FSCalendar 来 select 日期范围。
我发现这个库有 Swift 版本,但是范围 selection 版本仅适用于 Objective-C。所以我试图做的是使用桥接,但是我无法在 Swift.
中使用 RangePickerViewController
有人为 Swift 实施此库以使用日期范围吗? (e.x。我想 select 2 个日期作为我 select 出发和 Return 航班日期的航班应用程序的范围。)
尽管 FSCalendar 不直接支持范围选择,但它确实允许多选,这意味着在某些时候您可以自己处理范围选择。
因此,在 viewDidLoad()
中,您必须确保将日历 allowsMultipleSelection
属性 设置为 true
:
private weak var calendar: FSCalendar!
override func viewDidLoad() {
super.viewDidLoad()
calendar.allowsMultipleSelection = true
}
视图控制器应符合 FSCalendarDelegate
协议以处理 selecting/deselecting 范围的逻辑。
到目前为止我们需要声明范围的两个日期(开始日期和结束日期):
// first date in the range
private var firstDate: Date?
// last date in the range
private var lastDate: Date?
也是一个日期数组,用于保存 firstDate
和 lastDate
之间的起息日:
private var datesRange: [Date]?
然后将 didSelect date
和 didDeselect date
委托方法实现为:
func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) {
// nothing selected:
if firstDate == nil {
firstDate = date
datesRange = [firstDate!]
print("datesRange contains: \(datesRange!)")
return
}
// only first date is selected:
if firstDate != nil && lastDate == nil {
// handle the case of if the last date is less than the first date:
if date <= firstDate! {
calendar.deselect(firstDate!)
firstDate = date
datesRange = [firstDate!]
print("datesRange contains: \(datesRange!)")
return
}
let range = datesRange(from: firstDate!, to: date)
lastDate = range.last
for d in range {
calendar.select(d)
}
datesRange = range
print("datesRange contains: \(datesRange!)")
return
}
// both are selected:
if firstDate != nil && lastDate != nil {
for d in calendar.selectedDates {
calendar.deselect(d)
}
lastDate = nil
firstDate = nil
datesRange = []
print("datesRange contains: \(datesRange!)")
}
}
func calendar(_ calendar: FSCalendar, didDeselect date: Date, at monthPosition: FSCalendarMonthPosition) {
// both are selected:
// NOTE: the is a REDUANDENT CODE:
if firstDate != nil && lastDate != nil {
for d in calendar.selectedDates {
calendar.deselect(d)
}
lastDate = nil
firstDate = nil
datesRange = []
print("datesRange contains: \(datesRange!)")
}
}
datesRange
方法呢?
我没有在我的回答中提到它是为了让它更短,你所要做的就是 copy-paste 从 .
输出:
嗨,这是我的方法。
class CalendarDelegate: NSObject, FSCalendarDelegate {
func calendar(_ calendar: FSCalendar, shouldDeselect date: Date, at monthPosition: FSCalendarMonthPosition) -> Bool {
performDateDeselect(calendar, date: date)
return true
}
func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) {
performDateSelection(calendar)
}
private func performDateDeselect(_ calendar: FSCalendar, date: Date) {
let sorted = calendar.selectedDates.sorted { [=10=] < }
if let index = sorted.firstIndex(of: date) {
let deselectDates = Array(sorted[index...])
calendar.deselectDates(deselectDates)
}
}
private func performDateSelection(_ calendar: FSCalendar) {
let sorted = calendar.selectedDates.sorted { [=10=] < }
if let firstDate = sorted.first, let lastDate = sorted.last {
let ranges = datesRange(from: firstDate, to: lastDate)
calendar.selectDates(ranges)
}
}
func datesRange(from: Date, to: Date) -> [Date] {
if from > to { return [Date]() }
var tempDate = from
var array = [tempDate]
while tempDate < to {
tempDate = Calendar.current.date(byAdding: .day, value: 1, to: tempDate)!
array.append(tempDate)
}
return array
}
}
我将@Ahmed F 的代码转换为 Objective C。
创建以下变量
NSDate *firstDate;
NSDate *lastDate;
NSMutableArray *datesRange;
在 viewDidLoad 中添加以下行
datesRange = [NSMutableArray array];
calendar.allowsMultipleSelection = YES;
和 FSCalendar 的函数
- (NSArray <NSDate *> *)datesRange:(NSDate *)from andTo:(NSDate *)to {
if([from isLaterThan:to]) {
return [NSArray array];
}
NSDate *tempDate = from;
NSMutableArray <NSDate *> *arrDates = [NSMutableArray array];
[arrDates addObject:tempDate];
NSDateComponents *component = [[NSDateComponents alloc] init];
component.day = 1;
while ([tempDate isEarlierThan:to]) {
tempDate = [[NSCalendar currentCalendar] dateByAddingComponents:component toDate:tempDate options:0];
[arrDates addObject:tempDate];
}
return [NSArray arrayWithArray:arrDates];
}
- (void)calendar:(FSCalendar *)calendar didSelectDate:(NSDate *)date atMonthPosition:(FSCalendarMonthPosition)monthPosition {
if (firstDate == nil) {
firstDate = date;
datesRange = [NSMutableArray arrayWithObject:firstDate];
return;
}
if(firstDate != nil && lastDate == nil) {
if ([date isEarlierThan:firstDate]) {
[calendar deselectDate:firstDate];
firstDate = date;
datesRange = [NSMutableArray arrayWithObject:firstDate];
return;
}
NSArray<NSDate *> *range = [self datesRange:firstDate andTo:date];
lastDate = [range lastObject];
for (NSDate *d in range) {
[calendar selectDate:d];
}
datesRange = [NSMutableArray arrayWithArray:range];
return;
}
if (firstDate != nil && lastDate != nil) {
for (NSDate *d in calendar.selectedDates) {
[calendar deselectDate:d];
}
lastDate = nil;
firstDate = nil;
[datesRange removeAllObjects];
}
}
- (void)calendar:(FSCalendar *)calendar didDeselectDate:(NSDate *)date atMonthPosition:(FSCalendarMonthPosition)monthPosition {
if (firstDate != nil && lastDate != nil) {
for (NSDate *d in calendar.selectedDates) {
[calendar deselectDate:d];
}
lastDate = nil;
firstDate = nil;
[datesRange removeAllObjects];
}
}
我正在尝试在我的一个项目中使用 FSCalendar 来 select 日期范围。
我发现这个库有 Swift 版本,但是范围 selection 版本仅适用于 Objective-C。所以我试图做的是使用桥接,但是我无法在 Swift.
中使用 RangePickerViewController有人为 Swift 实施此库以使用日期范围吗? (e.x。我想 select 2 个日期作为我 select 出发和 Return 航班日期的航班应用程序的范围。)
尽管 FSCalendar 不直接支持范围选择,但它确实允许多选,这意味着在某些时候您可以自己处理范围选择。
因此,在 viewDidLoad()
中,您必须确保将日历 allowsMultipleSelection
属性 设置为 true
:
private weak var calendar: FSCalendar!
override func viewDidLoad() {
super.viewDidLoad()
calendar.allowsMultipleSelection = true
}
视图控制器应符合 FSCalendarDelegate
协议以处理 selecting/deselecting 范围的逻辑。
到目前为止我们需要声明范围的两个日期(开始日期和结束日期):
// first date in the range
private var firstDate: Date?
// last date in the range
private var lastDate: Date?
也是一个日期数组,用于保存 firstDate
和 lastDate
之间的起息日:
private var datesRange: [Date]?
然后将 didSelect date
和 didDeselect date
委托方法实现为:
func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) {
// nothing selected:
if firstDate == nil {
firstDate = date
datesRange = [firstDate!]
print("datesRange contains: \(datesRange!)")
return
}
// only first date is selected:
if firstDate != nil && lastDate == nil {
// handle the case of if the last date is less than the first date:
if date <= firstDate! {
calendar.deselect(firstDate!)
firstDate = date
datesRange = [firstDate!]
print("datesRange contains: \(datesRange!)")
return
}
let range = datesRange(from: firstDate!, to: date)
lastDate = range.last
for d in range {
calendar.select(d)
}
datesRange = range
print("datesRange contains: \(datesRange!)")
return
}
// both are selected:
if firstDate != nil && lastDate != nil {
for d in calendar.selectedDates {
calendar.deselect(d)
}
lastDate = nil
firstDate = nil
datesRange = []
print("datesRange contains: \(datesRange!)")
}
}
func calendar(_ calendar: FSCalendar, didDeselect date: Date, at monthPosition: FSCalendarMonthPosition) {
// both are selected:
// NOTE: the is a REDUANDENT CODE:
if firstDate != nil && lastDate != nil {
for d in calendar.selectedDates {
calendar.deselect(d)
}
lastDate = nil
firstDate = nil
datesRange = []
print("datesRange contains: \(datesRange!)")
}
}
datesRange
方法呢?
我没有在我的回答中提到它是为了让它更短,你所要做的就是 copy-paste 从
输出:
嗨,这是我的方法。
class CalendarDelegate: NSObject, FSCalendarDelegate {
func calendar(_ calendar: FSCalendar, shouldDeselect date: Date, at monthPosition: FSCalendarMonthPosition) -> Bool {
performDateDeselect(calendar, date: date)
return true
}
func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) {
performDateSelection(calendar)
}
private func performDateDeselect(_ calendar: FSCalendar, date: Date) {
let sorted = calendar.selectedDates.sorted { [=10=] < }
if let index = sorted.firstIndex(of: date) {
let deselectDates = Array(sorted[index...])
calendar.deselectDates(deselectDates)
}
}
private func performDateSelection(_ calendar: FSCalendar) {
let sorted = calendar.selectedDates.sorted { [=10=] < }
if let firstDate = sorted.first, let lastDate = sorted.last {
let ranges = datesRange(from: firstDate, to: lastDate)
calendar.selectDates(ranges)
}
}
func datesRange(from: Date, to: Date) -> [Date] {
if from > to { return [Date]() }
var tempDate = from
var array = [tempDate]
while tempDate < to {
tempDate = Calendar.current.date(byAdding: .day, value: 1, to: tempDate)!
array.append(tempDate)
}
return array
}
}
我将@Ahmed F 的代码转换为 Objective C。
创建以下变量
NSDate *firstDate;
NSDate *lastDate;
NSMutableArray *datesRange;
在 viewDidLoad 中添加以下行
datesRange = [NSMutableArray array];
calendar.allowsMultipleSelection = YES;
和 FSCalendar 的函数
- (NSArray <NSDate *> *)datesRange:(NSDate *)from andTo:(NSDate *)to {
if([from isLaterThan:to]) {
return [NSArray array];
}
NSDate *tempDate = from;
NSMutableArray <NSDate *> *arrDates = [NSMutableArray array];
[arrDates addObject:tempDate];
NSDateComponents *component = [[NSDateComponents alloc] init];
component.day = 1;
while ([tempDate isEarlierThan:to]) {
tempDate = [[NSCalendar currentCalendar] dateByAddingComponents:component toDate:tempDate options:0];
[arrDates addObject:tempDate];
}
return [NSArray arrayWithArray:arrDates];
}
- (void)calendar:(FSCalendar *)calendar didSelectDate:(NSDate *)date atMonthPosition:(FSCalendarMonthPosition)monthPosition {
if (firstDate == nil) {
firstDate = date;
datesRange = [NSMutableArray arrayWithObject:firstDate];
return;
}
if(firstDate != nil && lastDate == nil) {
if ([date isEarlierThan:firstDate]) {
[calendar deselectDate:firstDate];
firstDate = date;
datesRange = [NSMutableArray arrayWithObject:firstDate];
return;
}
NSArray<NSDate *> *range = [self datesRange:firstDate andTo:date];
lastDate = [range lastObject];
for (NSDate *d in range) {
[calendar selectDate:d];
}
datesRange = [NSMutableArray arrayWithArray:range];
return;
}
if (firstDate != nil && lastDate != nil) {
for (NSDate *d in calendar.selectedDates) {
[calendar deselectDate:d];
}
lastDate = nil;
firstDate = nil;
[datesRange removeAllObjects];
}
}
- (void)calendar:(FSCalendar *)calendar didDeselectDate:(NSDate *)date atMonthPosition:(FSCalendarMonthPosition)monthPosition {
if (firstDate != nil && lastDate != nil) {
for (NSDate *d in calendar.selectedDates) {
[calendar deselectDate:d];
}
lastDate = nil;
firstDate = nil;
[datesRange removeAllObjects];
}
}