zoukankan      html  css  js  c++  java
  • iOs 自定义UIView 日历的实现 Swift2.1

    学习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 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的写法

    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,  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,  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,  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,  rect.width - padding * 2 , height: padding + mergin + RowHeight * CGFloat(rowCount - 1) + 10 ))
            path.stroke()
            
            //path = UIBezierPath(rect: CGRect(x: padding + mergin, y: padding + mergin,  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)" )
        }
        
        
        
    }
  • 相关阅读:
    C#入门
    使用 OLEDB 及 SqlBulkCopy 将多个不在同一文件夹下的 ACCESS mdb 数据文件导入MSSQL
    aspose.word 读取word段落内容
    Jquery+Aajax 批量上传
    asp.net mvc web api Token验证
    iframe父页面和子页面获取元素和js变量
    JavaScrpt常用的封装方法
    ASP.NET MVC 导出Word报表
    Asp.net的对Excel文档的导入导出操作
    C++ 复制vector值到array,复制 array 到jintArray
  • 原文地址:https://www.cnblogs.com/TextEditor/p/4877163.html
Copyright © 2011-2022 走看看