【问题标题】:How to Select Range - FSCalendar in Swift?如何在 Swift 中选择范围 - FSCalendar?
【发布时间】:2018-04-16 11:37:48
【问题描述】:

我正在尝试在我的一个项目中使用FSCalendar 来选择日期范围。

我发现这个库有 Swift 版本,但是范围选择版本仅适用于 Objective-C。所以我试图做的是使用桥接,但是我无法在 Swift 中使用RangePickerViewController

是否有人为 Swift 实现了这个库以使用日期范围? (例如,我想选择 2 个日期作为航班应用程序的范围,我选择了出发和返回航班日期。)

【问题讨论】:

    标签: ios swift swift4 fscalendar


    【解决方案1】:

    虽然 FSCalendar 不直接支持范围选择,但它确实允许多选,这意味着在某些时候您可以自己处理范围选择。

    因此,在viewDidLoad() 中,您必须确保将日历allowsMultipleSelection 属性设置为true

    private weak var calendar: FSCalendar!
    
    override func viewDidLoad() {
        super.viewDidLoad()
    
        calendar.allowsMultipleSelection = true
    }
    

    视图控制器应遵循FSCalendarDelegate 协议来处理选择/取消选择范围的逻辑。

    到目前为止,我们需要声明该范围的两个日期(起始日期和结束日期):

    // first date in the range
    private var firstDate: Date?
    // last date in the range
    private var lastDate: Date?
    

    还有一个日期数组,用于保存firstDatelastDate 之间的生效日期:

    private var datesRange: [Date]?
    

    然后将didSelect datedidDeselect 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 方法呢?

    我没有在回答中提到它以使其更短,您所要做的就是从this answer复制粘贴它。

    输出:

    【讨论】:

    • 感谢您的回答。我会调查并回复你。
    • 您知道如何在 1 个屏幕中显示 2 个日历吗?现在我只有 1 个月的时间...
    • @FahimParkar 如果您的目标是在同一个视图控制器中添加两个日历,您应该通过说if calendar === firstCalendar 来检查您在委托方法中与哪个日历交谈
    • @FahimParkar 很高兴听到这个消息 ?
    • @AhmadF,您能帮我解决这个问题吗:github.com/WenchaoD/FSCalendar/issues/904 我可以通过将 Objective C 代码转换为 Swift 来实现 Range Picker,但开始日期选择颜色直到结束日期选择才会改变。
    【解决方案2】:

    嗨,这是我的方法。

    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 { $0 < $1 }
        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 { $0 < $1 }
        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
    }
    

    }

    【讨论】:

      【解决方案3】:

      我将@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];
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2022-06-13
        • 1970-01-01
        • 2019-02-24
        • 2018-09-27
        • 1970-01-01
        • 2015-04-05
        • 1970-01-01
        • 2014-09-01
        • 2021-11-26
        相关资源
        最近更新 更多