Reputation: 123
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:
Your help will be much appreciated.
Upvotes: 6
Views: 13421
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
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
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
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
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