iOS开发之自定义日历控件
前言
日常开发中经常会遇到日期选择,为了方便使用,简单封装了一个日历控件,在此抛砖引玉供大家参考。
效果
功能
- 支持单选、区间
- 支持默认选中日期
- 支持限制月份
- 支持过去、当前、未来模式
- 支持
frame、AutoLayout
原理
层次结构使用UIStackView布局,UICollectionView复用,背景使用DecorationView。
核心代码
日历核心代码在于计算每个月的日期,主要代码如下:
func month() -> [CLCalendarMonthModel] {
func day(with date: Date, section: Int) -> [CLCalendarDayModel] {
var newDate = date
let tatalDay = newDate.daysInMonth
let firstDay = max(0, newDate.weekday - 1)
let columns = Int(ceil(CGFloat(tatalDay + firstDay) / CGFloat(weekArray.count)))
var resultArray = [CLCalendarDayModel]()
for column in 0 ..< columns {
for weekDay in 0 ..< weekArray.count {
if column == 0,
weekDay <= firstDay - 1
{
resultArray.append(CLCalendarDayModel())
} else {
let subtitle: String? = {
guard !newDate.isToday else { return "今天" }
guard config.isShowLunarCalendar else { return nil }
guard let index = chinese.dateComponents([.day], from: newDate).day else { return nil }
return chineseDayArray[index - 1]
}()
let type: CLCalendarDayModel.CLCalendarDayType = {
guard !newDate.isToday else { return .today }
guard newDate.compare(todayDate) == .orderedDescending else { return .future }
return .past
}()
let dayModel = CLCalendarDayModel(title: "\(newDate.day)", date: newDate, subtitle: subtitle, type: type)
resultArray.append(dayModel)
newDate = newDate + 1.days
if beginDate?.year == dayModel.date?.year,
beginDate?.month == dayModel.date?.month,
beginDate?.day == dayModel.date?.day
{
startIndexPath = .init(row: 0, section: section)
}
guard (resultArray.count - firstDay) != tatalDay else { break }
}
}
}
return resultArray
}
var resultArray = [CLCalendarMonthModel]()
let month: Int = {
var value = 0
if config.type == .past {
value = config.limitMonth - 1
} else if config.type == .today {
value = config.limitMonth / 2
}
return value
}()
let start = todayDate - month.months
for i in 0 ..< config.limitMonth {
let date = start + i.months
let headerModel = CLCalendarMonthModel(headerText: date.format(with: "yyyy年MM月"),
month: date.format(with: "MM"),
daysArray: day(with: Date(year: date.year, month: date.month, day: 1), section: i))
resultArray.append(headerModel)
}
return resultArray
}
基础配置
struct CLCalendarConfig {
enum CLCalendarType {
case past
case today
case future
}
enum CLSelectType {
case single
case area
}
struct CLTouchType: OptionSet {
static let past = CLTouchType(rawValue: 1)
static let today = CLTouchType(rawValue: 1 << 1)
static let future = CLTouchType(rawValue: 1 << 2)
let rawValue: Int64
init(rawValue: Int64) {
self.rawValue = rawValue
}
}
struct CLColor {
var background = "#ffffff".uiColor
var topToolBackground = "#F4F4F4".uiColor
var topToolText = "#444444".uiColor
var topToolTextWeekend = "#3CCA79".uiColor
var sectionBackgroundText = "f2f2f2".uiColor
var selectStartBackground = "#4bce817f".uiColor
var selectBackground = "#afe9c77f".uiColor
var selectEndBackground = "#4bce817f".uiColor
var todayText = "#32cd32".uiColor
var titleText = "#555555".uiColor
var subtitleText = "#555555".uiColor
var selectTodayText = "#32cd32".uiColor
var selectTitleText = "#ffffff".uiColor
var selectSubtitleText = "#ffffff".uiColor
var failureTitleText = "#a9a9a9".uiColor
var failureSubtitleText = "#a9a9a9".uiColor
var failureBackground = "#dcdcdc32".uiColor
}
var color = CLColor()
var selectBegin: Date?
var selectEnd: Date?
var limitMonth = 12
var type = CLCalendarType.today
var selectType = CLSelectType.area
var touchType: CLTouchType = [.today, .past]
var isShowLunarCalendar = true
var insetsLayoutMarginsFromSafeArea = true
var headerHight = 50.0
}
总结
定制化开发请自行参考CLDemo修改 , 如果喜欢,欢迎star。
参考资料
iOS开发之自定义日历控件的更多相关文章
- iOS开发UI篇—UITableview控件基本使用
iOS开发UI篇—UITableview控件基本使用 一.一个简单的英雄展示程序 NJHero.h文件代码(字典转模型) #import <Foundation/Foundation.h> ...
- iOS开发UI篇—UITableview控件使用小结
iOS开发UI篇—UITableview控件使用小结 一.UITableview的使用步骤 UITableview的使用就只有简单的三个步骤: 1.告诉一共有多少组数据 方法:- (NSInteger ...
- javascript实例学习之六—自定义日历控件
基于之前上篇博客轻量级jquery,tool.js和base.js.自定义开发的base_datePicker插件,效果类似于jquery_ui的datePicker插件 //基于Base.js以及t ...
- iOS开发UI篇—UIScrollView控件实现图片缩放功能
iOS开发UI篇—UIScrollView控件实现图片缩放功能 一.缩放 1.简单说明: 有些时候,我们可能要对某些内容进行手势缩放,如下图所示 UIScrollView不仅能滚动显示大量内容,还能对 ...
- iOS开发UI篇—UIScrollView控件介绍
iOS开发UI篇—UIScrollView控件介绍 一.知识点简单介绍 1.UIScrollView控件是什么? (1)移动设备的屏幕⼤大⼩小是极其有限的,因此直接展⽰示在⽤用户眼前的内容也相当有限 ...
- iOS开发UI篇—UITableview控件简单介绍
iOS开发UI篇—UITableview控件简单介绍 一.基本介绍 在众多移动应⽤用中,能看到各式各样的表格数据 . 在iOS中,要实现表格数据展示,最常用的做法就是使用UITableView,UIT ...
- iOS开发UI篇—UIScrollView控件实现图片轮播
iOS开发UI篇—UIScrollView控件实现图片轮播 一.实现效果 实现图片的自动轮播 二.实现代码 storyboard中布局 代码: #import "YYV ...
- 【转】 iOS开发UI篇—UIScrollView控件实现图片轮播
原文:http://www.cnblogs.com/wendingding/p/3763527.html iOS开发UI篇—UIScrollView控件实现图片轮播 一.实现效果 实现图片的自动轮播 ...
- ios开发中关闭textview控件的虚拟键盘
在ios开发中,textfield控件在点击的时候出现虚拟键盘,关掉虚拟键盘可以通过虚拟键盘中的done button和点击view中的任意地方来关闭虚拟键盘. 1.第一种方法是textfield控件 ...
随机推荐
- Python 工匠: 异常处理的三个好习惯
前言 这是 "Python 工匠"系列的第 6 篇文章.(点击原文链接,可查看系列其他文章) 如果你用 Python 编程,那么你就无法避开异常,因为异常在这门语言里无处不在.打个 ...
- Luogu1868 饥饿的奶牛 (动态规划)
开始以为是贪心,10分:想了个DP估计会超时,一翻题解各路初中神仙,背包都有. \(n^2\)很好想,考虑单调性用二分优化出log #include <iostream> #include ...
- HCIA-datacom 4.2 实验二:本地AAA配置实验
关于本实验 AAA是Authentication(认证).Authorization(授权)和Accounting(计费)的简称,是网络安全的一种管理机制,提供了认证.授权.计费三种安全功能.这三种安 ...
- 新一代分布式实时流处理引擎Flink入门实战操作篇
@ 目录 安装部署 安装方式 Local(Standalone 单机部署) Standalone部署 Standalone HA部署 Flink On Yarn演示案例 概述 会话(Session)模 ...
- 基于 Apache Hudi 和DBT 构建开放的Lakehouse
本博客的重点展示如何利用增量数据处理和执行字段级更新来构建一个开放式 Lakehouse. 我们很高兴地宣布,用户现在可以使用 Apache Hudi + dbt 来构建开放Lakehouse. 在深 ...
- python一招完美搞定Chromedriver的自动更新
日常的web自动化过程中,我们常常用python selenium库来操纵Chrome浏览器实现网页的自动化.这其中有个比较头疼的问题:Chrome的更新频率非常频繁,与之对应的Chromedrive ...
- thinkphp5.1 cookie跨域、thinkphp5.1 session跨域、tp5.1cookie跨域
cookie跨域: //config/cookie.php return [ //... //仅7.3.0及以上适用 'samesite' => 'None', //是否加密cookie值,fa ...
- 使用 Elastic 技术栈构建 K8S 全栈监控 -2: 用 Metricbeat 对 Kubernetes 集群进行监控
文章转载自:https://www.qikqiak.com/post/k8s-monitor-use-elastic-stack-2/ 操作步骤 git clone https://github.co ...
- Traefik 2.0 暴露 Redis(TCP) 服务
文章转载自:https://mp.weixin.qq.com/s?__biz=MzU4MjQ0MTU4Ng==&mid=2247484452&idx=1&sn=0a17b907 ...
- Beats:使用Elastic Stack监控RabbitMQ