项目中有相册的功能,现在又要在相册中添加新的需求,将相册的图片以日历的形式显示。这里主要用到了Calendar这个类。下面介绍一下这个功能的实现,写了一个demo,demo只是写了一下日历的写法,并没有附上实际的图片数据,大家可以自己按自己的需求设计数据model进行图片赋值。
功能演示:
Calendar
Calendar是Swift中提供的日历类,它提供了大部分的关于日期的计算接口。这里我就不具体的展开介绍这个类的使用,我只列出在demo中用到的方法,简单的介绍它们的作用。
//调用Calendar类,创建实例对象
var myCalendar = Calendar.current
let currentDate = Date()
//获取指定日期是周几(默认周日是1,周一是2,依次类推)
let week: Int = myCalendar.ordinality(of: .day, in: .weekOfMonth, for: currentDate) ?? 0
//获取指定日期当月的天数
let dasOfMonth: Int = myCalendar.range(of: .day, in: .month, for: currentDate)?.count ?? 0
//获取指定日期之后天数的日期Date
var dateComponents = DateComponents()
dateComponents.day = 3
let data = myCalendar.date(byAdding: dateComponents, to: currentDate)
这几个都是非常常用的方法,更多的使用方法,大家可以自己去了解。
功能代码实现
这里主要是在于跳转到月份日期页面时,cell的日期计算和显示。我们需要确认:
- 该月的第一天是从周几开始。
- 确认该月的section中每个cell的日期。
- 该月section的cell数需要多少行显示。
- 判断每个cell的Date是否跟该月属于同一个月,属于:显示日期。不属于:显示空白。
OK下面开始上具体的项目代码:
- 创建一个工具类,来进行日期的计算和数据的处理。CalendarDateTool.swift
import UIKit
class CalendarDateTool: NSObject {
let formate = DateFormatter()
static let instance: CalendarDateTool = CalendarDateTool()
class func shared() -> CalendarDateTool {
return instance
}
//MARK: 日历显示行数
class func calendarGetRows(currentDate: Date) -> Int {
//当前日期(都是每月的1号)是星期几 (默认是周日为1,周一为2,依次类推)
let week: Int = Calendar.current.ordinality(of: .day, in: .weekOfMonth, for: currentDate) ?? 0
//当前月的天数
let daysOfMouth: Int = Calendar.current.range(of: .day, in: .month, for: currentDate)?.count ?? 0
//进行行数的计算,需理解。
let temp = daysOfMouth - (8 - week)
let rows = temp % 7 > 0 ? temp / 7 + 2 : temp / 7 + 1
return rows
}
//MARK: 获取选中月份第一天的日期Date
class func getCurrentDate(yearStr: String, mouthStr: String) -> Date {
let dateFormat = DateFormatter()
dateFormat.dateFormat = "yyyy-MM-dd"
let str = yearStr + "-" + mouthStr + "-" + "01"
let date = dateFormat.date(from: str)
return date!
}
//MARK:获取cell的日期 按照indexPath获取cell的日期
class func dateForCell(indexPath: IndexPath, currentDate: Date) -> Date {
let week: Int = Calendar.current.ordinality(of: .day, in: .weekOfMonth, for: currentDate) ?? 0
var dateComponents = DateComponents()
dateComponents.day = (1 - week) + indexPath.row
let date: Date = Calendar.current.date(byAdding: dateComponents, to: currentDate)!
return date
}
//MARK: 判断两个日期月份是否同一个月
class func checkSameMouth(dateOne: Date, dateTwo: Date) -> Bool {
let cal = Calendar.current
let yearOne: Int = cal.component(.year, from: dateOne)
let monthOne: Int = cal.component(.month, from: dateOne)
let yearTwo: Int = cal.component(.year, from: dateTwo)
let monthTwo: Int = cal.component(.month, from: dateTwo)
var rt: Bool = false
if yearOne == yearTwo && monthOne == monthTwo {
rt = true
} else {
rt = false
}
return rt
}
//MARK: cell得到日期
func getCellDateStrFromFormat(formatStr: String, cellDate: Date) -> String {
self.formate.dateFormat = formatStr
return self.formate.string(from: cellDate)
}
}
- 对UIColor扩展方法
import UIKit
extension UIColor {
//MARK: 随机赋色
class func randomColor() -> UIColor {
var returnColor = UIColor()
let color1 = UIColor.init(hexString: "#e8eaf2")
let color2 = UIColor.init(hexString: "#ecefef")
let color3 = UIColor.init(hexString: "#efefec")
let color4 = UIColor.init(hexString: "#f6f6f7")
let colorArr = [color1, color2, color3, color4]
let temp = Int(arc4random() % 4)
returnColor = colorArr[temp]
return returnColor
}
//MARK: 按色号进行赋色
convenience init(hexString: String) {
//处理数值
var cString = hexString.uppercased().trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
let length = (cString as NSString).length
//错误处理
if (length < 6 || length > 7 || (!cString.hasPrefix("#") && length == 7)){
//返回whiteColor
self.init(red: 0.0, green: 0.0, blue: 0.0, alpha: 1.0)
return
}
if cString.hasPrefix("#"){
cString = (cString as NSString).substring(from: 1)
}
//字符chuan截取
var range = NSRange()
range.location = 0
range.length = 2
let rString = (cString as NSString).substring(with: range)
range.location = 2
let gString = (cString as NSString).substring(with: range)
range.location = 4
let bString = (cString as NSString).substring(with: range)
//存储转换后的数值
var r:UInt32 = 0,g:UInt32 = 0,b:UInt32 = 0
//进行转换
Scanner(string: rString).scanHexInt32(&r)
Scanner(string: gString).scanHexInt32(&g)
Scanner(string: bString).scanHexInt32(&b)
//根据颜色值创建UIColor
self.init(red: CGFloat(r)/255.0, green: CGFloat(g)/255.0, blue: CGFloat(b)/255.0, alpha: 1.0)
}
}
- 工具类创建完毕,下面是封装的一个CalendarView,继承UIView
import UIKit
let WIDTH = UIScreen.main.bounds.width
let HEIGHT = UIScreen.main.bounds.height
let backColor = UIColor(red:0.95, green:0.95, blue:0.95, alpha:1.00)
class CalendarView: UIView, UICollectionViewDelegate, UICollectionViewDataSource {
let identifier = "pool"
let headerIdentifier = "header"
var navi: UINavigationController?
var collection: UICollectionView!
let mouthArr: Array<String> = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"]
let yearArr: Array<String> = ["2017", "2016", "2015", "2014", "2013"]
override init(frame: CGRect) {
super .init(frame: frame)
self.setUpUI()
}
func setUpUI() {
self.backgroundColor = backColor
let layout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(width: (WIDTH - 25) / 6, height: (WIDTH - 25) / 6)
layout.minimumInteritemSpacing = 3
layout.minimumLineSpacing = 5
layout.scrollDirection = .vertical
layout.sectionInset = UIEdgeInsets.init(top:0, left: 5, bottom: 0, right: 5)
layout.headerReferenceSize = CGSize(width: WIDTH, height: 50)
collection = UICollectionView.init(frame: CGRect.init(x: 0, y: 1, width: WIDTH, height: HEIGHT - 1), collectionViewLayout: layout)
collection.backgroundColor = UIColor.white
collection.delegate = self
collection.dataSource = self
collection.register(CalendarCollectionCell.self, forCellWithReuseIdentifier: identifier)
collection.register(CalendarOneHeader.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: headerIdentifier)
self.addSubview(collection)
}
//MARK: collectionViewDelegate
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 12
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collection.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath) as! CalendarCollectionCell
cell.mouthLabel.text = mouthArr[indexPath.row] + "月"
return cell
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return yearArr.count
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
if kind == UICollectionElementKindSectionHeader {
let reusableView = collection.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: headerIdentifier, for: indexPath) as! CalendarOneHeader
reusableView.yearLabel.text = yearArr[indexPath.section] + "年"
return reusableView
}
return UICollectionReusableView()
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let nextVC = CalendarControllerTwo()
let str = self.yearArr[indexPath.section] + "年" + self.mouthArr[indexPath.row] + "月"
nextVC.headerText = str
//处理选中月份的一号日期数据,传到下一页。
nextVC.currentDate = CalendarDateTool.getCurrentDate(yearStr: yearArr[indexPath.section], mouthStr: mouthArr[indexPath.row])
self.navi?.pushViewController(nextVC, animated: true)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
自定义的cell和头视图
cell
import UIKit
class CalendarCollectionCell: UICollectionViewCell {
var picture: UIImageView!
var mouthLabel: UILabel!
override init(frame: CGRect) {
super.init(frame: frame)
picture = UIImageView.init(frame: self.bounds)
picture.backgroundColor = UIColor.randomColor()
mouthLabel = UILabel.init(frame: CGRect(x: 0, y: 0, width: 50, height: 30))
mouthLabel.center = self.contentView.center
mouthLabel.textColor = UIColor.white
mouthLabel.font = UIFont.boldSystemFont(ofSize: 18)
mouthLabel.textAlignment = NSTextAlignment.center
configUI()
}
func configUI() {
self.contentView.addSubview(picture)
self.contentView.addSubview(mouthLabel)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
header
import UIKit
class CalendarOneHeader: UICollectionReusableView {
var yearLabel: UILabel!
override init(frame: CGRect) {
super .init(frame: frame)
yearLabel = UILabel.init(frame: CGRect(x: 18, y: 20, width: self.frame.width - 40, height: 18))
yearLabel.textAlignment = NSTextAlignment.left
yearLabel.font = UIFont.systemFont(ofSize: 13)
yearLabel.textColor = UIColor.gray
self.addSubview(yearLabel)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
- 创建跳转页面:月份页面。
import UIKit
class CalendarControllerTwo: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
let identifier = "pool"
let headerIdentifier = "header"
var collection: UICollectionView!
var headerText: String! //头视图的字符串
var currentDate: Date! //选中的月份的一号日期(Data)数据
override func viewDidLoad() {
super.viewDidLoad()
setUpUI()
}
func setUpUI() {
self.view.backgroundColor = backColor
let layout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(width: (WIDTH - 6) / 7, height: (WIDTH - 6) / 7)
layout.minimumLineSpacing = 1
layout.minimumInteritemSpacing = 1
layout.scrollDirection = .vertical
layout.sectionInset = UIEdgeInsets.init(top: 0, left: 0, bottom: 0, right: 0)
layout.headerReferenceSize = CGSize(width: WIDTH, height: 60)
collection = UICollectionView.init(frame: CGRect.init(x: 0, y: 1, width: WIDTH, height: HEIGHT - 1), collectionViewLayout: layout)
collection.backgroundColor = UIColor.white
collection.delegate = self
collection.dataSource = self
collection.register(CalendarCollectionCellTwo.self, forCellWithReuseIdentifier: identifier)
collection.register(CalendarTwoHeader.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: headerIdentifier)
self.view.addSubview(collection)
}
//MARK: collectionViewDelegate
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
if kind == UICollectionElementKindSectionHeader {
let reusableView = collection.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: headerIdentifier, for: indexPath) as! CalendarTwoHeader
reusableView.yearLabel.text = headerText
return reusableView
}
return UICollectionReusableView()
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
//获取该月份返回cell的个数方法
return CalendarDateTool.calendarGetRows(currentDate: currentDate) * 7
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collection.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath) as! CalendarCollectionCellTwo
let cellDate = CalendarDateTool.dateForCell(indexPath: indexPath, currentDate: currentDate)
cell.currentDate = currentDate
cell.cellDate = cellDate
return cell
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
自定义的cell和头视图
cell:
import UIKit
class CalendarCollectionCellTwo: UICollectionViewCell {
var picture: UIImageView!
var dayLabel: UILabel!
var cellDate = Date() {
didSet {
//判断是否为同一月份
if CalendarDateTool.checkSameMouth(dateOne: cellDate, dateTwo: currentDate) {
showDate()
} else {
showSpace()
}
}
}
var currentDate: Date!
override init(frame: CGRect) {
super.init(frame: frame)
picture = UIImageView.init(frame: self.bounds)
dayLabel = UILabel.init(frame: CGRect(x: self.frame.width - 25, y: self.frame.height - 25, width: 20, height: 20 ))
dayLabel.textColor = UIColor.white
dayLabel.font = UIFont.boldSystemFont(ofSize: 12)
dayLabel.textAlignment = NSTextAlignment.center
configUI()
}
func configUI() {
self.contentView.addSubview(picture)
self.contentView.addSubview(dayLabel)
}
//当cell的日期该月份为同月时正常显示cell的样式
func showDate() {
self.isUserInteractionEnabled = true
picture.backgroundColor = UIColor.randomColor()
let day = CalendarDateTool.shared().getCellDateStrFromFormat(formatStr: "dd", cellDate: cellDate)
dayLabel.text = day
}
//当不属于同一个月时,显示空白
func showSpace() {
self.isUserInteractionEnabled = false
picture.backgroundColor = UIColor.clear
dayLabel.text = ""
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
header:
import UIKit
class CalendarTwoHeader: UICollectionReusableView {
let labelWidth: CGFloat = (WIDTH - 6) / 7
let labelHeight: CGFloat = 15
var yearLabel: UILabel!
override init(frame: CGRect) {
super .init(frame: frame)
yearLabel = UILabel.init(frame: CGRect(x: 18, y: 15, width: self.frame.width - 40, height: 15))
yearLabel.textAlignment = NSTextAlignment.left
yearLabel.font = UIFont.systemFont(ofSize: 15)
yearLabel.textColor = UIColor.black
self.addSubview(yearLabel)
let label1 = UILabel.init(frame: CGRect.init(x: 0, y: yearLabel.frame.maxY + 10, width: labelWidth, height: labelHeight))
label1.text = "周日"
label1.textAlignment = NSTextAlignment.center
label1.font = UIFont.systemFont(ofSize: 10)
label1.textColor = UIColor.init(hexString: "#959595")
let label2 = UILabel.init(frame: CGRect.init(x: label1.frame.maxX + 1, y: label1.frame.minY, width: labelWidth, height: labelHeight))
label2.text = "周一"
label2.textAlignment = NSTextAlignment.center
label2.font = UIFont.systemFont(ofSize: 10)
label2.textColor = UIColor.init(hexString: "#959595")
let label3 = UILabel.init(frame: CGRect.init(x: label2.frame.maxX + 1, y: label1.frame.minY, width: labelWidth, height: labelHeight))
label3.text = "周二"
label3.textAlignment = NSTextAlignment.center
label3.font = UIFont.systemFont(ofSize: 10)
label3.textColor = UIColor.init(hexString: "#959595")
let label4 = UILabel.init(frame: CGRect.init(x: label3.frame.maxX + 1, y: label1.frame.minY, width: labelWidth, height: labelHeight))
label4.text = "周三"
label4.textAlignment = NSTextAlignment.center
label4.font = UIFont.systemFont(ofSize: 10)
label4.textColor = UIColor.init(hexString: "#959595")
let label5 = UILabel.init(frame: CGRect.init(x: label4.frame.maxX + 1, y: label1.frame.minY, width: labelWidth, height: labelHeight))
label5.text = "周四"
label5.textAlignment = NSTextAlignment.center
label5.font = UIFont.systemFont(ofSize: 10)
label5.textColor = UIColor.init(hexString: "#959595")
let label6 = UILabel.init(frame: CGRect.init(x: label5.frame.maxX + 1, y: label1.frame.minY, width: labelWidth, height: labelHeight))
label6.text = "周五"
label6.textAlignment = NSTextAlignment.center
label6.font = UIFont.systemFont(ofSize: 10)
label6.textColor = UIColor.init(hexString: "#959595")
let label7 = UILabel.init(frame: CGRect.init(x: label6.frame.maxX + 1, y: label1.frame.minY, width: labelWidth, height: labelHeight))
label7.text = "周六"
label7.textAlignment = NSTextAlignment.center
label7.font = UIFont.systemFont(ofSize: 10)
label7.textColor = UIColor.init(hexString: "#959595")
self.addSubview(label1)
self.addSubview(label2)
self.addSubview(label3)
self.addSubview(label4)
self.addSubview(label5)
self.addSubview(label6)
self.addSubview(label7)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
ok 这里就将所有的代码列出,demo中每个cell都添加了UIImageView空间,设计好自己的model数据,将照片的日期分类清楚,进行赋值就可以形成日历相册了。数据处理这块还需要自己想清楚,处理好。
最后
最后附上demo的地址https://github.com/Sufviay/CalendarDemo,供参考。