學習Swift有一個月了,動手寫一個UIView吧。swift
全部源代碼在最後,直接用就能夠了,第一次寫Swift,和C#,Java仍是有區別的ide
(博客園能夠考慮在代碼插入中添加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 0; } //這個月的最後一天 //先得到下個月的第一天,而後在此基礎上減去24小時 //注意這裏的時間Debug的時候是UTC func getLastDay(var year:Int,var month:Int) -> Int?{ let dateFormatter:NSDateFormatter = NSDateFormatter(); dateFormatter.dateFormat = "yyyy/MM/dd"; if month == 12 { month = 0 year++ } let targetDate:NSDate? = dateFormatter.dateFromString(String(format:"%04d/%02d/01",year,month+1)); if targetDate != nil { let orgDate = NSDate(timeInterval:(24*60*60)*(-1), 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的寫法spa
Objective-Ccode
unsigned unitFlags = NSCalendarUnitYear
| NSCalendarUnitMonth
| NSCalendarUnitDay
| NSCalendarUnitWeekday
| NSCalendarUnitHour
| NSCalendarUnitMinute
| NSCalendarUnitSecond;component
Swift 2.0orm
let unitFlags: NSCalendarUnit = [ .Year,
.Month,
.Day,
.Weekday,
.Hour,
.Minute,
.Second ]blog
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(0,text.length)) text.addAttribute(NSFontAttributeName, value: UIFont.boldSystemFontOfSize(NSDefaultFontSize),range:NSMakeRange(0,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 != 0 {self.PickedDay = pick } } //根據觸摸點獲取日期 func getDayByTouchPoint(touchpoint:CGPoint) -> Int { for day in DayRect{ if day.1.contains(touchpoint){ return day.0 } } return 0 }
最終效果以下圖,能夠實現點擊選擇日期。整個代碼,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 = 2015{ didSet{ if self.CurrentYear < 0 { self.CurrentYear = 2015 } setNeedsDisplay() } } @IBInspectable var CurrentMonth : Int = 10 { didSet{ if self.CurrentMonth < 0 || self.CurrentMonth > 12 { self.CurrentMonth = 1 } setNeedsDisplay() } } @IBInspectable var padding : CGFloat = 4 { didSet{ if (self.padding > 50 ) { self.padding = 50 } setNeedsDisplay() } } @IBInspectable var mergin : CGFloat = 4 { didSet{ if (self.mergin > 50 ) { self.mergin = 50 } setNeedsDisplay() } } @IBInspectable var RowHeight : CGFloat = 20{ didSet{ if (self.RowHeight > 100 ) { self.RowHeight = 100 } setNeedsDisplay() } } @IBInspectable var PickedDay : Int = 1 { didSet{ if (self.PickedDay < 0){ self.PickedDay = 1 } 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 0; } //這個月的最後一天 //先得到下個月的第一天,而後在此基礎上減去24小時 //注意這裏的時間Debug的時候是UTC func getLastDay(var year:Int,var month:Int) -> Int?{ let dateFormatter:NSDateFormatter = NSDateFormatter(); dateFormatter.dateFormat = "yyyy/MM/dd"; if month == 12 { month = 0 year++ } let targetDate:NSDate? = dateFormatter.dateFromString(String(format:"%04d/%02d/01",year,month+1)); if targetDate != nil { let orgDate = NSDate(timeInterval:(24*60*60)*(-1), 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 != 0 {self.PickedDay = pick } } //根據觸摸點獲取日期 func getDayByTouchPoint(touchpoint:CGPoint) -> Int { for day in DayRect{ if day.1.contains(touchpoint){ return day.0 } } return 0 } // 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 = 12; //繪製表頭 let UseableWidth :CGFloat = rect.width - (padding + mergin) * 2; let WeekdayColumnWidth : CGFloat = UseableWidth / 7 var leftside : CGFloat = padding + mergin for i in 0...6{ 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 = 1; 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 1...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 - 1) * 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/2) 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(0,text.length)) text.addAttribute(NSFontAttributeName, value: UIFont.boldSystemFontOfSize(NSDefaultFontSize),range:NSMakeRange(0,text.length)) } text.drawInRect(CellRect) DayRect[day] = CellRect //繪製了週日以後,須要新的一行 if weekday == 7 { rowCount++ } } //繪製外框 let path : UIBezierPath = UIBezierPath(rect: CGRect(x: padding, y: padding, width: rect.width - padding * 2 , height: padding + mergin + RowHeight * CGFloat(rowCount - 1) + 10 )) 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)" ) } }