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)" )
        }
        
        
        
    }
  • 相关阅读:
    XML错误信息Referenced file contains errors (http://www.springframework.org/schema/beans/spring-beans-4.0.xsd). For more information, right click on the message in the Problems View ...
    Description Resource Path Location Type Cannot change version of project facet Dynamic Web Module to 2.3.
    maven创建web报错Cannot read lifecycle mapping metadata for artifact org.apache.maven.plugins:maven-compiler-plugin:maven-compiler-plugin:3.5.1:runtime Cause: error in opening zip file
    AJAX跨域
    JavaWeb学习总结(转载)
    JDBC学习笔记
    Java动态代理之JDK实现和CGlib实现
    (转)看懂UML类图
    spring boot配置使用fastjson
    python3下django连接mysql数据库
  • 原文地址:https://www.cnblogs.com/TextEditor/p/4877163.html
Copyright © 2011-2022 走看看