EMontesMac
EMontesMac

Reputation: 123

How can I get the UI Calendar?

Could you help me with this question, please?

I only need to put a simple Calendar in one of the screens, and I do not have any idea of how can I obtain it, because this UI element is not in the IB.

My client wants the screen like the image below, without the UISegmentedControl (with list, day, month) that has the Calendar app on iPhone.

He wants to see just a calendar, and when you click in one of the days, another view will appear (FYI: view with data loaded from a website corresponding for that day).

http://craigl21.typepad.com/.a/6a00e008db59db8834010535e2d304970c-800wi

So, finally my questions are:

  1. How to obtain the Calendar?
  2. I have 'Today' right bar button item of the Navigation bar working (click and another view is loaded). I would like to know how can I put a similar function for the days of the calendar, which I suppose all of them are buttons and I do not know how can I access to them (as I do not know anything about the Calendar element yet).
  3. By default, today's date must be selected in blue when you load this Calendar view, and when you press any of the days, another view will be loaded. If today's date is selected initially, when I load the Calendar view, the new view with today's details would be loaded immediately? (how could avoid this behaviour?) or hopefully, the calendar would wait for my click on today's date (or any other date)?

Your help will be much appreciated.

Upvotes: 6

Views: 13421

Answers (5)

Blazej Kita
Blazej Kita

Reputation: 135

Try this:

protocol SelectedDay {
 func tap(y:Int,m:Int,d:Int) -> Void
}

class UICalendar: UIView {

    private var year:Int = 0
    private var month:Int  = 0
    private var day:Int  = 0
    private var last:Int = 0
    private var dayOfWeekFirst:Int = -1
    
    private var monthName:Dictionary<Int,String> = [ 1:"Styczeń",2:"Luty",3:"Marzec",4:"Kwiecień",5:"Maj",6:"Czerwiec",7:"Lipiec",8:"Sierpień",9:"Wrzesień",10:"Październik",11:"Listopad",12:"Grudzień" ]
    
    private let dayOfWeek:Dictionary<Int, String> = [ 1:"Pn",2:"Wt",3:"Śr",4:"Cz",5:"Pt",6:"Sb",7:"Nd" ]
    
    private var titleColorBg:UIColor = UIColor.init(red: 36/255, green: 36/255, blue: 143/255, alpha: 0.8)
    private var titleColorText:UIColor = .white
    
    private var dayColorBg:UIColor = UIColor.init(red: 36/255, green: 36/255, blue: 143/255, alpha: 0.5)
    private var dayColorText:UIColor = .white
   
    private var selectedColorBg:UIColor = UIColor.init(red: 36/255, green: 36/255, blue: 143/255, alpha: 0.5)
    private var selectedColorText:UIColor = .orange
    
    private var borderColor:UIColor = .white
 
    
    private var daysLabel:Dictionary<Int, UILabel> = [:]
    
  
    private var selected:SelectedDay? = nil
    
     
    
    struct day_info
    {
        var year:Int = 0
        var month:Int = 0
        var day:Int = 0
    }
    
    private var daysInfo:Dictionary<Int,day_info> = [:]
    
   
     //initWithFrame to init view from code
     override init(frame: CGRect) {
       super.init(frame: frame)
       setupView()
     }
     
     //initWithCode to init view from xib or storyboard
     required init?(coder aDecoder: NSCoder) {
       super.init(coder: aDecoder)
       setupView()
     }
    
    
     
     //common func to init our view
     private func setupView() {
     
        
       //get current date
        let date     = Date()
        let calendar = Calendar.current
        self.year    = calendar.component(.year, from: date)
        self.month   = calendar.component(.month, from: date)
        self.day     = calendar.component(.day, from: date)
        self.last    = self.getLastDay(year: self.year, month: self.month)
        self.dayOfWeekFirst = calendar.component(.weekday, from: date) - 1
        self.drawCalendar()
     }
    
   
    
    
     @objc private func press_day(recognized:UITapGestureRecognizer)
     {
        
        let label = recognized.view as! UILabel
        let info:day_info = self.daysInfo[label.tag]!
     
       
        if(self.selected != nil)
        {
            
            self.selected?.tap(y: info.year, m: info.month, d: info.day)
        }
     }
    
    @objc func change_month(recognized:UITapGestureRecognizer)
    {
        print("change month..")
        
        let label = recognized.view as! UILabel
        
        if(label.tag == -1) //goback
        {
            if(self.month == 1)
            { self.year -= 1; self.month = 12  }
            else {  self.month -= 1; }
        }
        
        if(label.tag == 1) //gonext..
        {
            if(self.month == 12)
            { self.year += 1; self.month = 1  }
            else {  self.month += 1; }
        }
        
        
        
    
        drawCalendar()
    }
    
    
    func selectDay( selected:SelectedDay )
    {
        self.selected = selected
    }
    
    private func drawCalendar()
    {
        
        
        self.last    = self.getLastDay(year: self.year, month: self.month)
        if(self.day > self.last) { self.day = self.last }
        
        let calendar = Calendar.current
        
        let formatter = DateFormatter()
        formatter.dateFormat =  "yyyy/MM/dd HH:mm"
        let date = formatter.date(from: String(self.year) + "/" + String(self.month) + "/01 10:00")
        
        
        self.dayOfWeekFirst = calendar.component(.weekday, from: date!) - 1
        
        
        
        print("Selected: \(self.year) \(self.month) \(self.day), \(self.last), \(self.dayOfWeekFirst) ")
        print(date)
        
        
        //for select day
        let cal = Calendar.current
        let nowDay:Int = cal.component(.day, from: Date() )
        let nowMont:Int = cal.component(.day, from: Date())
        let nowYear:Int = cal.component(.year, from: Date())
        
        
        var numDay:Int = -1
        self.daysLabel.removeAll()
        self.daysInfo.removeAll()
      
        
        
        
        //clear view..
        self.subviews.forEach { view in view.removeFromSuperview() }
       
        //rows of cal..
        let rowsSV:UIStackView = UIStackView(frame: CGRect(x: 0, y: 0, width: self.bounds.width, height: self.bounds.height ) )
        rowsSV.axis = .vertical
      //  rowsSV.backgroundColor = self.borderColor
        rowsSV.alignment = .fill
        rowsSV.spacing = 2
        rowsSV.distribution = .fillProportionally
        self.addSubview(rowsSV)
    
        
        for k in 0...8
        {
            let ui:UIStackView = UIStackView()
            ui.axis = .horizontal
            ui.alignment = .fill
            ui.distribution = .fillEqually
            ui.spacing = 2
           // ui.backgroundColor = self.borderColor
            
            rowsSV.addArrangedSubview(ui)
            
            
            //first line..
            if( k == 0)
            {
                //prev button..
                let uiPrev = UILabel()
                uiPrev.text = " < "
                uiPrev.backgroundColor = self.titleColorBg
                uiPrev.textColor = self.titleColorText
                uiPrev.textAlignment = .center
                uiPrev.tag = -1
                uiPrev.isUserInteractionEnabled = true
                uiPrev.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(change_month(recognized:))))
                ui.addArrangedSubview(uiPrev)
                
                //month title
                let uiTitle = UILabel()
                uiTitle.text = String(self.year) + " " + self.monthName[self.month]! 
                uiTitle.backgroundColor =   self.titleColorBg
                uiTitle.textColor = self.titleColorText
                uiTitle.textAlignment = .center
                ui.addArrangedSubview(uiTitle)
                
                //next..
                let uiNext = UILabel()
                uiNext.text = " > "
                uiNext.backgroundColor = self.titleColorBg
                uiNext.textColor = self.titleColorText
                uiNext.textAlignment = .center
                uiNext.tag = 1
                uiNext.isUserInteractionEnabled = true
                uiNext.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(change_month(recognized:))))
                ui.addArrangedSubview(uiNext)
            }
            
            //day of week..
            if(k == 2)
            {
                let d1 = UILabel()
                d1.text = self.dayOfWeek[1]
                d1.backgroundColor = self.titleColorBg
                d1.textColor = self.titleColorText
                d1.textAlignment = .center
                ui.addArrangedSubview(d1)
                
                let d2 = UILabel()
                d2.text = self.dayOfWeek[2]
                d2.backgroundColor = self.titleColorBg
                d2.textColor = self.titleColorText
                d2.textAlignment = .center
                ui.addArrangedSubview(d2)
                
                let d3 = UILabel()
                d3.text = self.dayOfWeek[3]
                d3.backgroundColor = self.titleColorBg
                d3.textColor = self.titleColorText
                d3.textAlignment = .center
                ui.addArrangedSubview(d3)
                
                let d4 = UILabel()
                d4.text = self.dayOfWeek[4]
                d4.backgroundColor = self.titleColorBg
                d4.textColor = self.titleColorText
                d4.textAlignment = .center
                ui.addArrangedSubview(d4)
                
                let d5 = UILabel()
                d5.text = self.dayOfWeek[5]
                d5.backgroundColor = self.titleColorBg
                d5.textColor = self.titleColorText
                d5.textAlignment = .center
                ui.addArrangedSubview(d5)
                
                let d6 = UILabel()
                d6.text = self.dayOfWeek[6]
                d6.backgroundColor = self.titleColorBg
                d6.textColor = self.titleColorText
                d6.textAlignment = .center
                ui.addArrangedSubview(d6)
                
                let d7 = UILabel()
                d7.text = self.dayOfWeek[7]
                d7.backgroundColor = self.titleColorBg
                d7.textColor = self.titleColorText
                d7.textAlignment = .center
                ui.addArrangedSubview(d7)
            }
            
            if(k > 2)
            {
                //add 7 spaces
                for inx in 1...7
                {
                    if(numDay == -1 &&  (self.dayOfWeekFirst==inx  || (inx == 7 && self.dayOfWeekFirst == 0)  ) )
                    {
                        numDay = 1
                    }
                    
                    if(numDay > self.last)
                    {
                        numDay = -2 //dont count..
                    }
                   
                    if(numDay > 0)
                    {
                        let dx = UILabel()
                        dx.text =   String( numDay)
                        dx.backgroundColor =  self.dayColorBg
                        dx.textColor = self.dayColorText
                        dx.textAlignment = .center
                        dx.tag = numDay
                        
                        if(nowDay == numDay  )
                        {
                            dx.backgroundColor =  self.selectedColorBg
                            dx.textColor = self.selectedColorText
                        }
                        
                        ui.addArrangedSubview(dx)
                      
                        
                        dx.isUserInteractionEnabled = true
                        dx.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(press_day(recognized:))))
                        
                        self.daysLabel[numDay] = dx
                        
                        var info:day_info = day_info()
                        info.year = year
                        info.month = month
                        info.day = numDay
                        self.daysInfo[numDay] = info
                        
                        
                        
                        numDay += 1
                        
                    }else
                    {
                        let dx = UILabel()
                        dx.text =   "  "
                        dx.backgroundColor = self.dayColorBg
                        dx.textColor = self.dayColorText
                        dx.textAlignment = .center
                        ui.addArrangedSubview(dx)
                    }
                }
            }
        }
    }
    
    
    /**
          Get last day of month..
     */
    private func getLastDay(year:Int, month:Int) -> Int
    {
        var ret:Int = -1
        
        switch month {
        case 1:
            ret = 31
            break
        case 2:
             break
        case 3:
            ret = 31
            break
        case 4:
            ret = 30
            break
        case 5:
            ret = 31
            break
        case 6:
            ret = 30
            break
        case 7:
            ret = 31
            break
        case 8:
            ret = 31
            break
        case 9:
            ret = 30
            break
        case 10:
            ret = 31
            break
        case 11:
            ret = 30
            break
        case 12:
            ret = 31
            break
        default:
            print("bad num")
        }
        
        if(month == 2)
        {
            ret = 28
            
            let t4 = year % 4
            let l100 = year % 100
            let l400 = year % 400
            
            if(t4 == 0 && l100 != 0)
            {
                ret = 29
            }
            
            if(l400 == 0)
            {
                ret = 29
            }
        }
        return ret
    }
}

And in ViewController (viewDidLoad) + implement protocol in your class:

let calendar = UICalendar(frame: CGRect(x: 5, y: 5, width: self.calView.bounds.width-50, height: self.calView.bounds.height-10))
 calendar.selectDay(selected: self)

self.calView.addSubview(calendar)

Upvotes: 0

aporat
aporat

Reputation: 5932

The NSCalendar classes are only used for date calculation and apple does not provide a standard calendar element as a part of their UIKit library. However, take a look on this github project, someone published a project that contains a custom made calender UI.

https://github.com/guicocoa/calendar.

It's all open source ofcourse, so you can adjust the design and functionality as you need

Upvotes: 4

Soniya
Soniya

Reputation: 608

You can use https://github.com/devinross/tapkulibrary calendar for you app If you want to add some event on date selection then you need to import events from your app to native iphone calendar? You should use EventKit for that.

Upvotes: 3

Dan Ray
Dan Ray

Reputation: 21893

In addition to the calendar app that @aporat suggests, you should check out Kal, which is a very full-featured recreation of the Calendar app's interface, and is open source and editable and customizable.

It is kind of crazy that there's no native calendar UI, but there it is.

Upvotes: 0

StuStirling
StuStirling

Reputation: 16191

The calendar you ar looking for is the NSGregorianCalendar. Used with NSDateComponents and NSDate it is possible to create a custom calendar like the one shown in your link.

You need a custom object for the tiles with a property of NSDate which is where you can get the label date from using NSDateComponents. You can also assign a method to the delegate so when your date cell object is touched it tells the delegate it was touched and you can then do what you want...

Upvotes: 0

Related Questions