iOS开发之自定义日历控件
<h1 id="前言">前言</h1><p>日常开发中经常会遇到日期选择,为了方便使用,简单封装了一个日历控件,在此抛砖引玉供大家参考。</p>
<h1 id="效果">效果</h1>
<p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0e00e2632d5540acaa892038ceadd6b9~tplv-k3u1fbpfcp-watermark.image?" alt="效果图" loading="lazy"></p>
<h1 id="功能">功能</h1>
<ul class="contains-task-list">
<li class="task-list-item"><input class="task-list-item-checkbox" checked="" disabled="" type="checkbox"><label> 支持单选、区间</label></li>
<li class="task-list-item"><input class="task-list-item-checkbox" checked="" disabled="" type="checkbox"><label> 支持默认选中日期</label></li>
<li class="task-list-item"><input class="task-list-item-checkbox" checked="" disabled="" type="checkbox"><label> 支持限制月份</label></li>
<li class="task-list-item"><input class="task-list-item-checkbox" checked="" disabled="" type="checkbox"><label> 支持过去、当前、未来模式</label></li>
<li class="task-list-item"><input class="task-list-item-checkbox" checked="" disabled="" type="checkbox"><label> 支持<code>frame</code>、<code>AutoLayout</code></label></li>
</ul>
<h1 id="原理">原理</h1>
<p>层次结构使用<code>UIStackView</code>布局,<code>UICollectionView</code>复用,背景使用<code>DecorationView</code>。</p>
<h1 id="核心代码">核心代码</h1>
<p>日历核心代码在于计算每个月的日期,主要代码如下:</p>
<pre><code>func month() -> {
func day(with date: Date, section: Int) -> {
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 = ()
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
}()
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 = ()
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
}
</code></pre>
<h1 id="基础配置">基础配置</h1>
<pre><code class="language-swift">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
}
</code></pre>
<h1 id="总结">总结</h1>
<p>定制化开发请自行参考CLDemo修改 , 如果喜欢,欢迎star。</p>
<h1 id="参考资料">参考资料</h1>
<ol>
<li>
<p>DateToolsSwift</p>
</li>
<li>
<p>UICollectionView:装饰视图 Decoration View</p>
</li>
<li>
<p>使用UIStackView来简化iOS的界面布局</p>
</li>
</ol>
</div>
<div id="MySignature" role="contentinfo">
<div>作者:JmoVxia</div>
<div>出处:http://www.cnblogs.com/JmoVxia/
</div>
本文版权归作者所有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。<br><br>
来源:https://www.cnblogs.com/JmoVxia/p/16822128.html
頁:
[1]