100行代码swift从零实现一个iOS日历

首先实现日历最重要的是数据,UI的话大家可以自己实现,demo中有简单的日历实现,有了数据源不论是使用UIKit还是swiftUI都非常简单 iOS开发的时候很多时候会用到日历组件,很多时候网上的三方库实在臃肿,其实我们可以快速实现一个

代码如下

ini 复制代码
let tool = CalendarTool(start: "2025-04-01", startWeek: .sunday)
// 数组里面就是 2025-04-01 月份数据(包含上个月和下个月补齐部分)
let arr = tool.getDaysInMonthArr()

源码如下,如果需要更多功能可以自己修改

github.com/AblerSong/S...

ini 复制代码
//(sunday = 1,monday = 2,...)
enum Weekday: Int {
    case sunday = 1, monday, tuesday, wednesday, thursday, friday, saturday
}

class CalendarModel {
    init(date: Date, type: Int = 0) {
        self.date = date
        self.type = type
    }
    
    // pre: -1; current: 0; next: 1
    let type: Int
    // date
    let date: Date
    // yyyy-MM-dd
    private lazy var dateString: String = {
        CalendarTool.dateFormatter.string(from: date)
    }()
    private lazy var dateArr = dateString.components(separatedBy: "-").map{ Int($0)! }
    
    private lazy var chineseDateString: String = {
        CalendarTool.chineseDateFormatter.string(from: date)
    }()
    private lazy var chineseDateArr = chineseDateString.components(separatedBy: "-")
    
    // yyyy
    lazy var year = dateArr[0]
    // MM
    lazy var month = dateArr[1]
    // dd
    lazy var day = dateArr[2]
    
    lazy var chineseMonth = {
        let str = chineseDateArr[1]
        if str.hasPrefix("闰") {
            return "闰" + CalendarTool.chineseMonths[Int(str.dropFirst())! - 1]
        }
        return CalendarTool.chineseMonths[Int(str)! - 1]
    }()
    
    lazy var chineseDay = {
        CalendarTool.chineseDays[Int(chineseDateArr[2])! - 1]
    }()
}

class CalendarTool {
    /// init
    /// - Parameters:
    ///   - startString: start date string yyyy-MM-dd
    ///   - startWeek: default:  sunday
    init(start: String, startWeek: Weekday = .sunday) {
        self.startString = start
        self.startWeek = startWeek.rawValue
    }
    
    func getDaysInMonthArr() -> [CalendarModel] {
        guard let startDate = dateFormatter.date(from: startString),
              let endDate = calendar.date(byAdding:.month, value: 1, to: startDate) else {
            return []
        }
        
        var dateArray: [CalendarModel] = []
        
        var currentDate = startDate;
        
        {
            var arr: [CalendarModel] = []
            var week = calendar.dateComponents([.weekday], from: currentDate).weekday
            while week != startWeek {
                currentDate = calendar.date(byAdding:.day, value: -1, to: currentDate)!
                arr.append(CalendarModel(date: currentDate, type: -1))
                week = calendar.dateComponents([.weekday], from: currentDate).weekday
            }
            dateArray = Array(arr.reversed())
        }()
        
        currentDate = startDate
        while currentDate < endDate {
            dateArray.append(CalendarModel(date: currentDate))
            currentDate = calendar.date(byAdding:.day, value: 1, to: currentDate)!
        }
        
        {
            var week = calendar.dateComponents([.weekday], from: currentDate).weekday
            while week != startWeek {
                dateArray.append(CalendarModel(date: currentDate, type: 1))
                currentDate = calendar.date(byAdding:.day, value: 1, to: currentDate)!
                week = calendar.dateComponents([.weekday], from: currentDate).weekday
            }
        }()
        return dateArray
    }
    
    private var dateFormatter: DateFormatter { CalendarTool.dateFormatter }
    
    private var chineseDateFormatter: DateFormatter { CalendarTool.chineseDateFormatter }
    
    private var calendar: Calendar { CalendarTool.calendar }
    
    private  let startWeek: Int
    
    private let startString: String
    
    static let dateFormatter = {
        // Lock down the East Eighth Time Zone and 24 - hour format; modify it yourself if needed.
        let dateFormatter = DateFormatter()
        dateFormatter.calendar = Calendar(identifier:.iso8601)
        dateFormatter.locale = Locale(identifier: "zh_CN")
        dateFormatter.timeZone = TimeZone(identifier: "Asia/Shanghai")
        dateFormatter.dateFormat = "yyyy-MM-dd"
        return dateFormatter
    }()
    
    static let chineseDateFormatter = {
        // Lock down the East Eighth Time Zone and 24 - hour format; modify it yourself if needed.
        let dateFormatter = DateFormatter()
        dateFormatter.calendar = Calendar(identifier: .chinese)
        dateFormatter.locale = Locale(identifier: "zh_CN")
        dateFormatter.timeZone = TimeZone(identifier: "Asia/Shanghai")
        dateFormatter.dateFormat = "yyyy-MM-dd"
        return dateFormatter
    }()
    
    private static let calendar = Calendar(identifier:.iso8601)
    
    static let chineseMonths = ["正月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "冬月", "腊月"]
    
    static let chineseDays = ["初一", "初二", "初三", "初四", "初五", "初六", "初七", "初八", "初九", "初十", "十一", "十二", "十三", "十四", "十五", "十六", "十七", "十八", "十九", "二十", "廿一", "廿二", "廿三", "廿四", "廿五", "廿六", "廿七", "廿八", "廿九", "三十"]
    
}
相关推荐
sweet丶12 小时前
UIWindowScene 使用指南:掌握 iOS 多窗口架构
ios
崽崽长肉肉16 小时前
swift中的知识总结(一)
ios·swift
Yakamoz18 小时前
Swift Array的写时复制
swift
2501_9151063219 小时前
HTTP 协议详解,HTTP 协议在真实运行环境中的表现差异
网络·网络协议·http·ios·小程序·uni-app·iphone
汉秋21 小时前
SwiftUI 中的 compositingGroup():真正含义与渲染原理
swiftui·swift
柯南二号21 小时前
【大前端】【iOS】iOS 真实项目可落地目录结构方案
前端·ios
2501_9160074721 小时前
iOS与Android符号还原服务统一重构实践总结
android·ios·小程序·重构·uni-app·iphone·webview
汉秋1 天前
SwiftUI 中的 @ViewBuilder 全面解析
swiftui·swift
二流小码农1 天前
鸿蒙开发:自定义一个圆形动画菜单
android·ios·harmonyos
00后程序员张1 天前
fastlane 结合 appuploader 命令行实现跨平台上传发布 iOS App
android·ios·小程序·https·uni-app·iphone·webview