iOS swift自定义日历

27 篇文章 0 订阅

swift自定义日历(暂不支持滑动切换)

拒绝转载,抄袭更不允许!!!!求别污染分享环境
原图是这样的
请添加图片描述

功能介绍

  1. 暂不支持滑动切换月份,navigator右边是切换月份,每切换一次的月份会网络请求新的数据。
  2. 当月的下一个月不能点击
  3. 星期六日样式不一样,点击到当前cell的样式不一样,还没到的日期样式不一样,且不能点击(这优先级高)
  4. 当月的话是默认点击当天的位置,若非本月默认第一个(可做有数据的第一个)
  5. 数据返回的不是以每一天来返回,要对数据的时间进行遍历分析
  6. 若点击到没有数据的cell,底部的信息框显示一样的信息

日历原理

其实就是一个collectionview,第一天在星期几为了前面空多少个,有多少天就是确定collectionview的item有多少个(第一天的index + 天数)。collectionviewDataSource负责处理返回的数据,这就要把返回的数据的时间转换成day,然后判断day是否等于显示的天相等。再把数据放入。collectionviewdelegate负责点击事件判断,已点、未点、不能点

时间逻辑核心代码(工具类)

有获取当前月、上下月的第一天是星期几,当前月有多少天,date转string,string转date

class DateTools: NSObject {
/// Date转换String
    ///
    /// - Parameters:
    ///   - date: 日期
    ///   - format: 格式
    /// - Returns: 字符串日期

    class func stringFromDate(date: Date, format: String = "yyyy-MM-dd HH:mm:ss") -> String {
        let formatter = DateFormatter.init()
        formatter.locale = Locale(identifier: "zh_CN")
        formatter.dateFormat = format
        let dateString = formatter.string(from: date)
        return dateString
    }
    
    /// 上个月
    ///
    /// - Parameter date: 当前日期
    /// - Returns: 上月日期
    class func lastMonth(_ date: Date) -> Date {
        var dateCom = DateComponents()
        dateCom.month = -1
        let newDate = (Calendar.current as NSCalendar).date(byAdding: dateCom, to: date, options: NSCalendar.Options.matchStrictly)
        return newDate!
    }
    
    /// 下个月
    ///
    /// - Parameter date: 当前日期
    /// - Returns: 下个月日期
    class func nextMonth(_ date: Date) -> Date {
        var dateCom = DateComponents()
        let abc = 1
        dateCom.month = +abc
        let newDate = (Calendar.current as NSCalendar).date(byAdding: dateCom, to: date, options: NSCalendar.Options.matchStrictly)
        return newDate!
    }
    
    /// 当月的天数
    ///
    /// - Parameter date: 日期
    /// - Returns: 天数
    class func daysInCurrMonth(date: Date) -> Int {
        let days: NSRange = (Calendar.current as NSCalendar).range(of: NSCalendar.Unit.day, in: NSCalendar.Unit.month, for: date)
        return days.length
    }
    
    /// 当前月份的第一天是周几
    ///
    /// - Parameter date: 当前日期
    /// - Returns: 周几
    class func firstDayIsWeekInMonth(date: Date) -> Int {
        var calender = Calendar.current
        calender.firstWeekday = 1
        var com = (calender as NSCalendar).components([NSCalendar.Unit.year, NSCalendar.Unit.month, NSCalendar.Unit.day], from: date)
        com.day = 1
        let firstDay = calender.date(from: com)
        let firstWeek = (calender as NSCalendar).ordinality(of: NSCalendar.Unit.weekday, in: NSCalendar.Unit.weekOfMonth, for: firstDay!)
        return firstWeek - 1
    }
    
    /// 当前月份的几号
    ///
    /// - Parameter date: 当前月份
    /// - Returns: 几号
    class func day(_ date: Date) -> Int {
        let com = (Calendar.current as NSCalendar).components([NSCalendar.Unit.year, NSCalendar.Unit.month, NSCalendar.Unit.day], from: date)
        return com.day!
    }

实现逻辑

collectrionview的创建


// 数据使用要跟日匹配
    var count = 0
    var lastDay: String = ""
    var toDetailDate: String = "" //传出的日期
    let margin: CGFloat = 10.0
    let paddingLeft: CGFloat = 20.0
    var fullMoonRecordModel: FullMoonRecordModel?
    let itemWidth: CGFloat = (SCREEN_WIDTH - 100)/7.0
    fileprivate var OFFSET:CGFloat = AppDelegate.phoneType.VG_IS_IPhoneX_All ? 44:25
    fileprivate var identifier: String = "daysCell"
    fileprivate var date = Date()
    fileprivate var isCurrentMonth: Bool = true //是否当月
    fileprivate var currentMonthTotalDays: Int = 0 //当月的总天数
    var firstDayIsWeekInMonth: Int = 0 //每月的一号对于的周几
    fileprivate var lastSelectedItemIndex: IndexPath? //获取最后一次选中的索引
    let today: String = String(DateTools.day(Date()))  //当天几号

public lazy var calendarCollectionView: UICollectionView = {
        let layout = UICollectionViewFlowLayout()
        //layout.sectionInset = UIEdgeInsetsMake(0, 0, 0, 0)
        layout.itemSize = CGSize(width: itemWidth, height: itemWidth*1.325)
        layout.minimumLineSpacing = margin
        layout.minimumInteritemSpacing = margin
        
//        let vWidth: CGFloat = SCREEN_WIDTH - paddingLeft * 2
//        let tempRect = CGRect(x: paddingLeft, y: self.calendarHeadView.frame.maxY + 20 + OFFSET, width: vWidth, height: 300)
        let calendarCollectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: layout)
//        calendarCollectionView.frame = CGRect.zero
//        calendarCollectionView.collectionViewLayout = layout
        calendarCollectionView.backgroundColor = UIColor.makeColorBy_RGB(r: 242, g: 242, b: 242, a: 1.0)
        calendarCollectionView.dataSource = self
        calendarCollectionView.delegate = self
        calendarCollectionView.register(DaysCell.self, forCellWithReuseIdentifier: self.identifier)
        return calendarCollectionView
    }()

collectionview的实现(代码会删掉一些,敬请原谅,如有疑问可以直接私聊我)

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: self.identifier, for: indexPath) as! DaysCell
        cell.clearDaysLabelStyle()
        
        
        var day = 0
        let index = indexPath.row
        cell.classHour.text = ""
        cell.timeFace.text = ""
        if index < self.firstDayIsWeekInMonth {
            cell.daysLabel.text = ""
            cell.backgroundColor = UIConstants.color_002
//            cell.daysLabel.backgroundColor = UIConstants.color_002
        } else {
            day = index - self.firstDayIsWeekInMonth + 1
            cell.daysLabel.text = String(day)
            if model?.data?.count ?? 0 > count{
                if model?.data?[count].date != nil{
                    let hasday = Date.getDay(date: model?.data?[count].date ?? "")
                    if lastDay == hasday{
                        count += 1
                        day -= 1
                        
                    }
                    if String(day) == hasday{
                        lastDay = hasday
                        cell.model = model?.data?[count]
                        if model?.data?[count].expendcnt != 0{
                            //整数判断
                            var remainClass: String = ""
                            if model?.data?[count].expendcnt ?? 0.0 == floor(model?.data?[count].expendcnt ?? 0){

                            }else{

                            }

                        }else{

                        }
                        count += 1
                        
                    }
                }
                
            }
            
            cell.backgroundColor = UIColor.white
            cell.isSelectedItem = false
            cell.daysLabel.textColor = UIColor.init(hex: "333333")
            cell.timeFace.textColor = UIColor.init(hex: "666666")
            cell.classHour.textColor = UIColor.init(hex: "1797CE")
//            if originPointArray.contains(day) {
//                cell.isPointHidden = true
//            }
            cell.isWeekend = false
            cell.isDisable = false
            if isCurrentMonth {
                //当天
                if cell.daysLabel.text == today {
                    let cellModel = cell.model
                    cell.clickBack = { [weak self] in
                        self?.clickCell(cellModel: cellModel, today: self?.today ?? "")
                    }
                    cell.isSelectedItem = true
                    cell.backgroundColor = UIColor.init(hex: "1797CE")
//                    cell.backgroundColor =
//                    cell.isSelectedItem = false
                    cell.daysLabel.textColor = UIColor.white
                    cell.timeFace.textColor = UIColor.white
                    cell.classHour.textColor = .white
//                    collectionView.selectItem(at: indexPath, animated: true, scrollPosition: .centeredVertically)
                    self.lastSelectedItemIndex = indexPath
                }
                
                //当月当天以前的日期置灰,不可点击
                let itemValue = cell.daysLabel.text!
                let currDay = Int(itemValue)
                if currDay! > Int(today)! {
                    cell.isDisable = true
                    cell.backgroundColor = UIConstants.color_002
//                    cell.daysLabel.backgroundColor = UIConstants.color_002
                }else{
                    if index%7 == 0 || index%7 == 6{
                        cell.isDisable = true
                        cell.isWeekend = true
                    }else{
                        cell.isWeekend = false
                        cell.isDisable = false
                    }
                }
                
            }
            else {
                //非当前自然月的1号默认选中
                if cell.daysLabel.text == "1" {
                    var fcellModel:dayRecordData? = dayRecordData()
                    if model?.data?.count ?? 0 > count{
                            fcellModel = model?.data?[count]
                    }
                    cell.clickBack = { [weak self] in
                        self?.clickCell(cellModel: fcellModel, today: "1")
                    }
                    cell.isSelectedItem = true
                    self.lastSelectedItemIndex = indexPath
//                    collectionView.selectItem(at: indexPath, animated: true, scrollPosition: .centeredVertically)
//                    cell.isSelectedItem = false
                } else {
                    cell.isSelectedItem = false
                }
                if index%7 == 0 || index%7 == 6{
                    cell.isDisable = true
                    cell.isWeekend = true
                }else{
                    cell.isWeekend = false
                    cell.isDisable = false
                }
            }
        }
        
        return cell
    }

点击事件处理

//UICollectionViewDelegate
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        let currentCell = collectionView.cellForItem(at: indexPath) as! DaysCell
        
        //是否已经选中
        guard !currentCell.isSelectedItem else {
            return
        }
        
        //是否有值
        let itemText: String = currentCell.daysLabel.text!
        guard !itemText.isEmpty else {
            return
        }
        
        let curDate = Date()
        let today = DateTools.day(curDate)
        let currDay = Int(itemText)
        
        //选中日期小于当天并且非当月
        if self.isCurrentMonth && currDay! > today {
            return
        }
        
        //获取上一次选中的item
        let preCell = collectionView.cellForItem(at: self.lastSelectedItemIndex!) as! DaysCell
        preCell.isSelectedItem = false
        
        //获取当前选中的item
        currentCell.isSelectedItem = true
        self.lastSelectedItemIndex = indexPath
        if currentCell.classHour.text != "" || currentCell.timeFace.text != ""{
            bottomView.isHidden = false
            bottomView.isUserInteractionEnabled = true
            toImageView.isHidden = false
            let Monthday = currentCell.model?.date ?? ""
            let dateFormatter = DateFormatter()
            dateFormatter.dateFormat = "yyyy-MM-dd"
            let d = dateFormatter.date(from: Monthday)
            toDetailDate = Monthday
            bottomDay.text = String("\(d?.changeToString(formatterString: "M月d日") ?? "")·")
            var remainClass: String = ""
            if currentCell.model?.expendcnt ?? 0.0 == floor(currentCell.model?.expendcnt ?? 0){
                remainClass = String(Int(currentCell.model?.expendcnt ?? 0))
            }else{
                remainClass = String(currentCell.model?.expendcnt ?? 0.0)
            }
            if currentCell.model?.faceCnt != 0 && currentCell.model?.expendcnt != 0{
                bottomComment.text = "刷脸\(currentCell.model?.faceCnt ?? 0)次/扣减\(remainClass)课时"
            }else if currentCell.model?.faceCnt == 0 && currentCell.model?.expendcnt == 0{
                bottomComment.text = ""
            }else if currentCell.model?.expendcnt == 0{
                bottomComment.text = "刷脸\(currentCell.model?.faceCnt ?? 0)次"
            }else{
                bottomComment.text = "扣减\(remainClass)课时"
            }
            timeLabel.text = currentCell.model?.lastFaceInfo?.punchtime ?? ""
            if timeLabel.text == ""{
                bottomView.isUserInteractionEnabled = false
                toImageView.isHidden = true
                timeLabel.text = "当日暂无刷脸记录"
            }
            addressLabel.text = currentCell.model?.lastFaceInfo?.address ?? ""
            
        }else{
            bottomView.isHidden = false
            let mon = DateTools.stringFromDate(date: date, format: "M")
            let day:String = currentCell.daysLabel.text ?? ""
            bottomDay.text = "\(mon)\(day)日"
            timeLabel.text = "当日暂无刷脸记录"
            bottomComment.text = ""
            bottomView.isUserInteractionEnabled = false
            addressLabel.text = ""
            toImageView.isHidden = true
        }
    }

clickCell函数不会给出来,但原理就是底部的信息框的处理

func clickCell(cellModel:, today: String){

切换月历处理事件(完整代码)

@objc func lastAction() {
        self.date = DateTools.lastMonth(date)
        let monDay = DateTools.stringFromDate(date: date, format: "yyyy-MM")
        self._initCalendarInfo()
        count = 0
        lastDay = ""
        lastMon?(monDay)
        bottomView.isHidden = true
        if isCurrentMonth {
            nextMonthButton.isEnabled = false
        }else{
            nextMonthButton.isEnabled = true
        }
    }
    
    @objc func nextAction() {
        self.date = DateTools.nextMonth(date)
        print("date")
        print(date)
        count = 0
        let monDay = DateTools.stringFromDate(date: date, format: "yyyy-MM")
        self._initCalendarInfo()
        bottomView.isHidden = true
        lastDay = ""
        nextMon?(monDay)
        if isCurrentMonth {
            nextMonthButton.isEnabled = false
        }else{
            nextMonthButton.isEnabled = true
        }
    }

vc就负责对事件的处理、传递数据、网络请求而已,所以没必要添上去了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值