学习Swift有一个月了,动手写一个UIView吧。

所有源代码在最后,直接用就可以了,第一次写Swift,和C#,Java还是有区别的

(博客园可以考虑在代码插入中添加Swift的着色了)

1  函数准备。Swift的日历函数,随着版本的变化,变动很大。

    //MARK: - Calendar
//按照苹果的习惯,周日放在第一位
let weekdayForDisplay = ["周日","周一","周二","周三","周四","周五","周六"] //获取周 周日:1 - 周六:7
func getWeekDay(year:Int,month:Int,day:Int) ->Int{
let dateFormatter:NSDateFormatter = NSDateFormatter();
dateFormatter.dateFormat = "yyyy/MM/dd";
let date:NSDate? = dateFormatter.dateFromString(String(format:"%04d/%02d/%02d",year,month,day));
if date != nil {
let calendar:NSCalendar = NSCalendar.currentCalendar()
let dateComp:NSDateComponents = calendar.components(NSCalendarUnit.NSWeekdayCalendarUnit, fromDate: date!)
return dateComp.weekday;
}
return ;
} //这个月的最后一天
//先获得下个月的第一天,然后在此基础上减去24小时
//注意这里的时间Debug的时候是UTC
func getLastDay(var year:Int,var month:Int) -> Int?{
let dateFormatter:NSDateFormatter = NSDateFormatter();
dateFormatter.dateFormat = "yyyy/MM/dd";
if month == {
month =
year++
}
let targetDate:NSDate? = dateFormatter.dateFromString(String(format:"%04d/%02d/01",year,month+));
if targetDate != nil { let orgDate = NSDate(timeInterval:(**)*(-), sinceDate: targetDate!)
let str:String = dateFormatter.stringFromDate(orgDate)
return Int((str as NSString).componentsSeparatedByString("/").last!);
} return nil;
}

下面是NSDateCompents的一个坑,Swift 1 和 Swift 2 写法不一样

        let today = NSDate()
let calendar = NSCalendar(identifier: NSGregorianCalendar)
let comps:NSDateComponents = calendar!.components([NSCalendarUnit.Year,NSCalendarUnit.Month,NSCalendarUnit.Day], fromDate: today)

Swift 2 OptionSetType ,比较一下OC和Swift的写法

Objective-C

unsigned unitFlags = NSCalendarUnitYear
                   | NSCalendarUnitMonth
                   | NSCalendarUnitDay
                   | NSCalendarUnitWeekday
                   | NSCalendarUnitHour
                   | NSCalendarUnitMinute
                   | NSCalendarUnitSecond;

Swift
2.0

let unitFlags: NSCalendarUnit = [
.Year,
                                 
.Month,
                                 
.Day,
                                 
.Weekday,
                                 
.Hour,
                                 
.Minute,
                                 
.Second ]

Swift
1.2

let unitFlags: NSCalendarUnit =
.CalendarUnitYear
                              | .CalendarUnitMonth
                              | .CalendarUnitDay
                              | .CalendarUnitWeekday
                              | .CalendarUnitHour
                              | .CalendarUnitMinute
                              | .CalendarUnitSecond

Swift2.0 的语法和1.2有区别  
OptionSetType

2.接下来就是绘图,绘图就是各种被塞尔曲线

重点如下

如何居中

        let paragraph = NSMutableParagraphStyle()
        paragraph.alignment = NSTextAlignment.Center
       
let text  =  NSMutableAttributedString(string: weekdayForDisplay[i],attributes: [NSParagraphStyleAttributeName: paragraph])
        let CellRect = CGRect(x: leftside  , y:padding + mergin, width: WeekdayColumnWidth, height: RowHeight)
        text.drawInRect(CellRect) 红字粗体
        text.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor(),range:NSMakeRange(,text.length))
        text.addAttribute(NSFontAttributeName, value: UIFont.boldSystemFontOfSize(NSDefaultFontSize),range:NSMakeRange(,text.length))

3.接下来是如何捕获点击事件

由于是全手工绘制日历的格子,所以,就用OnTouchBegan事件的属性获得点击位置,根据位置得知被按下的区域隶属于哪个日子。

    //记录每天的格子的Rect
var DayRect = [Int:CGRect]() override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let SignleTouch = touches.first!
let Touchpoint = SignleTouch.locationInView(self)
let pick = getDayByTouchPoint(Touchpoint)
print("TouchPoint : X = \(Touchpoint.x) Y = \(Touchpoint.y) Day: \(pick)") if pick != {self.PickedDay = pick }
} //根据触摸点获取日期
func getDayByTouchPoint(touchpoint:CGPoint) -> Int {
for day in DayRect{
if day..contains(touchpoint){
return day.
}
}
return
}

最终效果如下图,可以实现点击选择日期。整个代码,8个小时可以完成。

现在的问题是,如果选择的日子变化了,我不知道怎么告诉上层的 ViewController,SelectDateChanged。

如果可以的话,最好能够出现 ActionConnection,可以拖曳连线,将Action和代码绑定。谁知道怎么做吗?

//
// CalendarView.swift
// PlanAndTarget
//
// Created by scs on 15/10/13.
// Copyright © 2015年 scs. All rights reserved.
// import UIKit @IBDesignable
class CalendarView: UIView {
//MARK: - Inspectable
@IBInspectable
var CurrentYear : Int = {
didSet{
if self.CurrentYear < {
self.CurrentYear =
}
setNeedsDisplay()
}
} @IBInspectable
var CurrentMonth : Int = {
didSet{
if self.CurrentMonth < || self.CurrentMonth > {
self.CurrentMonth =
}
setNeedsDisplay()
}
} @IBInspectable
var padding : CGFloat = {
didSet{
if (self.padding > ) {
self.padding =
}
setNeedsDisplay()
}
} @IBInspectable
var mergin : CGFloat = {
didSet{
if (self.mergin > ) {
self.mergin =
}
setNeedsDisplay()
}
} @IBInspectable
var RowHeight : CGFloat = {
didSet{
if (self.RowHeight > ) {
self.RowHeight =
}
setNeedsDisplay()
}
} @IBInspectable
var PickedDay : Int = {
didSet{
if (self.PickedDay < ){
self.PickedDay =
}
let lastDay = getLastDay( CurrentYear, month: CurrentMonth)
if (self.PickedDay > lastDay!){
self.PickedDay = lastDay!
}
setNeedsDisplay()
}
} //MARK: - Calendar
//按照苹果的习惯,周日放在第一位
let weekdayForDisplay = ["周日","周一","周二","周三","周四","周五","周六"] //获取周 周日:1 - 周六:7
func getWeekDay(year:Int,month:Int,day:Int) ->Int{
let dateFormatter:NSDateFormatter = NSDateFormatter();
dateFormatter.dateFormat = "yyyy/MM/dd";
let date:NSDate? = dateFormatter.dateFromString(String(format:"%04d/%02d/%02d",year,month,day));
if date != nil {
let calendar:NSCalendar = NSCalendar.currentCalendar()
let dateComp:NSDateComponents = calendar.components(NSCalendarUnit.NSWeekdayCalendarUnit, fromDate: date!)
return dateComp.weekday;
}
return ;
} //这个月的最后一天
//先获得下个月的第一天,然后在此基础上减去24小时
//注意这里的时间Debug的时候是UTC
func getLastDay(var year:Int,var month:Int) -> Int?{
let dateFormatter:NSDateFormatter = NSDateFormatter();
dateFormatter.dateFormat = "yyyy/MM/dd";
if month == {
month =
year++
}
let targetDate:NSDate? = dateFormatter.dateFromString(String(format:"%04d/%02d/01",year,month+));
if targetDate != nil { let orgDate = NSDate(timeInterval:(**)*(-), sinceDate: targetDate!)
let str:String = dateFormatter.stringFromDate(orgDate)
return Int((str as NSString).componentsSeparatedByString("/").last!);
} return nil;
} //MARK: - Event
//记录每天的格子的Rect
var DayRect = [Int:CGRect]() override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let SignleTouch = touches.first!
let Touchpoint = SignleTouch.locationInView(self)
let pick = getDayByTouchPoint(Touchpoint)
print("TouchPoint : X = \(Touchpoint.x) Y = \(Touchpoint.y) Day: \(pick)") if pick != {self.PickedDay = pick }
} //根据触摸点获取日期
func getDayByTouchPoint(touchpoint:CGPoint) -> Int {
for day in DayRect{
if day..contains(touchpoint){
return day.
}
}
return
} // Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func drawRect(rect: CGRect) { let paragraph = NSMutableParagraphStyle()
paragraph.alignment = NSTextAlignment.Center
//查资料可知默认字体为12
let NSDefaultFontSize : CGFloat = ; //绘制表头
let UseableWidth :CGFloat = rect.width - (padding + mergin) * ;
let WeekdayColumnWidth : CGFloat = UseableWidth /
var leftside : CGFloat = padding + mergin
for i in ...{
let text = NSMutableAttributedString(string: weekdayForDisplay[i],attributes: [NSParagraphStyleAttributeName: paragraph])
let CellRect = CGRect(x: leftside , y:padding + mergin, width: WeekdayColumnWidth, height: RowHeight)
text.drawInRect(CellRect)
leftside += WeekdayColumnWidth
} //绘制当月每天
var rowCount = ;
leftside = padding + mergin
let today = NSDate()
let calendar = NSCalendar(identifier: NSGregorianCalendar)
let comps:NSDateComponents = calendar!.components([NSCalendarUnit.Year,NSCalendarUnit.Month,NSCalendarUnit.Day], fromDate: today) //Clear
DayRect.removeAll() for day in ...getLastDay(CurrentYear,month:CurrentMonth)!{
let weekday = getWeekDay(CurrentYear, month: CurrentMonth, day: day)
let text = NSMutableAttributedString(string: String(day), attributes: [NSParagraphStyleAttributeName: paragraph])
let LeftTopX = leftside + CGFloat(weekday - ) * WeekdayColumnWidth
let LeftTopY = padding + mergin + RowHeight * CGFloat(rowCount)
let CellRect :CGRect = CGRect(x: LeftTopX, y: LeftTopY, width: WeekdayColumnWidth, height: RowHeight)
if (PickedDay == day){
//选中的日子,UI效果
let PickRectPath = UIBezierPath(roundedRect: CellRect, cornerRadius: RowHeight/)
UIColor.blueColor().colorWithAlphaComponent(0.3).setFill()
PickRectPath.fill()
} if (comps.year == CurrentYear && comps.month == CurrentMonth && comps.day == day){
text.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor(),range:NSMakeRange(,text.length))
text.addAttribute(NSFontAttributeName, value: UIFont.boldSystemFontOfSize(NSDefaultFontSize),range:NSMakeRange(,text.length))
} text.drawInRect(CellRect)
DayRect[day] = CellRect
//绘制了周日之后,需要新的一行
if weekday == { rowCount++ }
} //绘制外框
let path : UIBezierPath = UIBezierPath(rect: CGRect(x: padding, y: padding, width: rect.width - padding * , height: padding + mergin + RowHeight * CGFloat(rowCount - ) + ))
path.stroke() //path = UIBezierPath(rect: CGRect(x: padding + mergin, y: padding + mergin, width: rect.width - (padding + mergin) * 2 , height: rect.height - (padding + mergin) * 2))
//path.stroke() print("LastDay Of 2015/10 : \(getLastDay(CurrentYear, month: CurrentMonth))" )
print("2015/10/18 : \(weekdayForDisplay[getWeekDay(CurrentYear, month: CurrentMonth, day: 18) - 1] )" )
print("Calendar Size Height: \(rect.height) Width: \(rect.width)" )
} }

iOs 自定义UIView 日历的实现 Swift2.1的更多相关文章

  1. IOS自定义UIView

    IOS中一般会用到几种方式自定义UIView 1.继承之UIView的存代码的自定义View 2.使用xib和代码一起使用的自定义View 3.存xib的自定义View(不需要业务处理的那种) 本文主 ...

  2. OpenGL ES: iOS 自定义 UIView 响应屏幕旋转

    iOS下使用OpenGL 如果使用GLKit View 那么不用担心屏幕旋转的问题,说明如下: If you change the size, scale factor, or drawable pr ...

  3. IOS xib和代码自定义UIView

    https://www.jianshu.com/p/1bcc29653085 总结的比较好 iOS开发中,我们常常将一块View封装起来,以便于统一管理内部的子控件. 下面就来说说自定义View的封装 ...

  4. 【iOS自定义键盘及键盘切换】详解

    [iOS自定义键盘]详解 实现效果展示: 一.实现的协议方法代码 #import <UIKit/UIKit.h> //创建自定义键盘协议 @protocol XFG_KeyBoardDel ...

  5. iOS自定义的UISwitch按钮

    UISwitch开关控件 开关代替了点选框.开关是到目前为止用起来最简单的控件,不过仍然可以作一定程度的定制化. 一.创建 UISwitch* mySwitch = [[ UISwitchalloc] ...

  6. iOS 自定义layer的两种方式

    在iOS中,你能看得见摸得着的东西基本都是UIView,比如一个按钮,一个标签,一个文本输入框,这些都是UIView: 其实UIView之所以能显示在屏幕上,完全是因为它内部的一个图层 在创建UIVi ...

  7. iOS自定义组与组之间的距离以及视图

    iOS自定义组与组之间的距离以及视图 //头视图高度 - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(N ...

  8. iOS 自定义转场动画

    代码地址如下:http://www.demodashi.com/demo/12955.html 一.总效果 本文记录分享下自定义转场动画的实现方法,具体到动画效果:新浪微博图集浏览转场效果.手势过渡动 ...

  9. iOS 自定义转场动画浅谈

    代码地址如下:http://www.demodashi.com/demo/11612.html 路漫漫其修远兮,吾将上下而求索 前记 想研究自定义转场动画很久了,时间就像海绵,挤一挤还是有的,花了差不 ...

随机推荐

  1. [nRF51822] 5、 霸屏了——详解nRF51 SDK中的GPIOTE(从GPIO电平变化到产生中断事件的流程详解)

    :由于在大多数情况下GPIO的状态变化都会触发应用程序执行一些动作.为了方便nRF51官方把该流程封装成了GPIOTE,全称:The GPIO Tasks and Events (GPIOTE) . ...

  2. ci框架里rewrite示例

    ci里新建应用app,入口文件app.php. Nginx 这里附上vhost配置 app.52fhy.com.conf server { listen 80; server_name app.52f ...

  3. 《Effective Java》—— 对于所有对象都通用的方法

    本节主要涉及Object中通用的一些方法,比如equals,hashCode,toString,clone,finalize等等 覆盖equals时请遵守通用约定 equals方法实现的等价关系: 自 ...

  4. 关于js中的同步和异步

    最近看到前端面试问到js中的同步和异步,这个问题该怎么回答? 梳理一下,js对于异步的处理,很多人的第一反应是ajax,这只能说是对了一半. 1.个人觉得,js中,最基础的异步是setTimeout和 ...

  5. POJ1014 解题报告(DFS)

    题目在此:http://poj.org/problem?id=1014 要看清题意呢,题中要求输入的是价值分别为1,2,3,4,5,6的大理石的个数,而不是6块价值为输入数字的大理石!选这个题主要想练 ...

  6. Android开发之广播

    广播是Android开发中的一个重要的功能,在Android里面有各式各样的广播,比如:电池的状态变化.信号的强弱状态.电话的接听和短信的接收等等,现在给大家简单介绍一下系统发送.监听这些广播的机制. ...

  7. JAVA设计模式《二》

    上一篇为大家介绍了一下设计模式中的责任链模式,本篇为大家介绍一下关于设计模式中的单例模式与模板方法模式.单例模式的作用在于,保证应用中某个实例有且只有一个,单例模式又被分为:饱汉模式与饿汉模式,两者的 ...

  8. Android_TextView之跑马灯效果

    对于android控件中的TextView,相信大家一定不陌生,在显示文本内容时十分方便.不过我在使用时遇到一个小问题,就是当文字交多时,如何为用户进行展示.今天就为大家介绍一种解决方案--跑马灯效果 ...

  9. 解决firefox和IE9对icon font字体的跨域访问问题

    何为跨域访问,为什么会有跨域限制?一切还得从浏览器的同源策略说起. 同源策略:是浏览器最核心也是最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能会受到影响,可以说Web是构建在同源策略基础 ...

  10. Python函数参数默认值的陷阱和原理深究"

    本文将介绍使用mutable对象作为Python函数参数默认值潜在的危害,以及其实现原理和设计目的 本博客已经迁移至: http://cenalulu.github.io/ 本篇博文已经迁移,阅读全文 ...