diff --git a/RDVCalendarView.xcodeproj/project.pbxproj b/RDVCalendarView.xcodeproj/project.pbxproj index beb976f..5d71192 100644 --- a/RDVCalendarView.xcodeproj/project.pbxproj +++ b/RDVCalendarView.xcodeproj/project.pbxproj @@ -13,8 +13,6 @@ 62C2389217CB463C009B4090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 62C2388817CB463C009B4090 /* InfoPlist.strings */; }; 62C2389317CB463C009B4090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 62C2388A17CB463C009B4090 /* main.m */; }; 62C2389A17CB472B009B4090 /* RDVAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 62C2389917CB472B009B4090 /* RDVAppDelegate.m */; }; - 62C238A117CB4E97009B4090 /* RDVCalendarWeekDaysHeader.m in Sources */ = {isa = PBXBuildFile; fileRef = 62C238A017CB4E97009B4090 /* RDVCalendarWeekDaysHeader.m */; }; - 62C238A417CB6814009B4090 /* RDVCalendarMonthView.m in Sources */ = {isa = PBXBuildFile; fileRef = 62C238A317CB6814009B4090 /* RDVCalendarMonthView.m */; }; 62F77D3617BE0080009873CE /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 62F77D3517BE0080009873CE /* UIKit.framework */; }; 62F77D3817BE0080009873CE /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 62F77D3717BE0080009873CE /* Foundation.framework */; }; 62F77D3A17BE0080009873CE /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 62F77D3917BE0080009873CE /* CoreGraphics.framework */; }; @@ -36,10 +34,6 @@ 62C2388E17CB463C009B4090 /* RDVCalendarView-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RDVCalendarView-Prefix.pch"; sourceTree = ""; }; 62C2389817CB472B009B4090 /* RDVAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RDVAppDelegate.h; sourceTree = ""; }; 62C2389917CB472B009B4090 /* RDVAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RDVAppDelegate.m; sourceTree = ""; }; - 62C2389F17CB4E97009B4090 /* RDVCalendarWeekDaysHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RDVCalendarWeekDaysHeader.h; sourceTree = ""; }; - 62C238A017CB4E97009B4090 /* RDVCalendarWeekDaysHeader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RDVCalendarWeekDaysHeader.m; sourceTree = ""; }; - 62C238A217CB6813009B4090 /* RDVCalendarMonthView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RDVCalendarMonthView.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; - 62C238A317CB6814009B4090 /* RDVCalendarMonthView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = RDVCalendarMonthView.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 62F77D3217BE0080009873CE /* RDVCalendarView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RDVCalendarView.app; sourceTree = BUILT_PRODUCTS_DIR; }; 62F77D3517BE0080009873CE /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 62F77D3717BE0080009873CE /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; @@ -143,10 +137,6 @@ 62F77D5617BE00BB009873CE /* RDVCalendarView.m */, 62F77D5817BE0105009873CE /* RDVCalendarDayCell.h */, 62F77D5917BE0105009873CE /* RDVCalendarDayCell.m */, - 62C2389F17CB4E97009B4090 /* RDVCalendarWeekDaysHeader.h */, - 62C238A017CB4E97009B4090 /* RDVCalendarWeekDaysHeader.m */, - 62C238A217CB6813009B4090 /* RDVCalendarMonthView.h */, - 62C238A317CB6814009B4090 /* RDVCalendarMonthView.m */, ); path = RDVCalendarView; sourceTree = ""; @@ -225,8 +215,6 @@ 62C2389317CB463C009B4090 /* main.m in Sources */, 62C2389A17CB472B009B4090 /* RDVAppDelegate.m in Sources */, B46DECE11823FE5400D4A823 /* RDVExampleViewController.m in Sources */, - 62C238A117CB4E97009B4090 /* RDVCalendarWeekDaysHeader.m in Sources */, - 62C238A417CB6814009B4090 /* RDVCalendarMonthView.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/RDVCalendarView/RDVCalendarDayCell.m b/RDVCalendarView/RDVCalendarDayCell.m index 0e8e4ec..16bd4f5 100644 --- a/RDVCalendarView/RDVCalendarDayCell.m +++ b/RDVCalendarView/RDVCalendarDayCell.m @@ -53,6 +53,7 @@ - (id)initWithReuseIdentifier:(NSString *)reuseIdentifier { _textLabel = [[UILabel alloc] init]; [_textLabel setTextColor:[UIColor blackColor]]; + [_textLabel setHighlightedTextColor:[UIColor whiteColor]]; [_textLabel setBackgroundColor:[UIColor clearColor]]; [_textLabel setFont:[UIFont systemFontOfSize:20]]; [_contentView addSubview:_textLabel]; @@ -89,6 +90,7 @@ - (void)setSelected:(BOOL)selected animated:(BOOL)animated { } _selected = selected; + _highlighted = NO; void (^block)() = ^{ if (selected) { @@ -122,6 +124,7 @@ - (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated { } _highlighted = highlighted; + _selected = NO; void (^block)() = ^{ if (highlighted) { @@ -148,13 +151,8 @@ - (void)setHighlighted:(BOOL)highlighted { #pragma mark - Cell reuse - (void)prepareForReuse { - if ([self isSelected]) { - [self setSelected:NO]; - } - - if ([self isHighlighted]) { - [self setHighlighted:NO]; - } + [self setSelected:NO]; + [self setHighlighted:NO]; [[self textLabel] setText:@""]; } diff --git a/RDVCalendarView/RDVCalendarMonthView.h b/RDVCalendarView/RDVCalendarMonthView.h deleted file mode 100644 index 9e0a70d..0000000 --- a/RDVCalendarView/RDVCalendarMonthView.h +++ /dev/null @@ -1,56 +0,0 @@ -// RDVCalendarMonthView.h -// RDVCalendarView -// -// Copyright (c) 2013 Robert Dimitrov -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#import - -@protocol RDVCalendarMonthViewDelegate; -@class RDVCalendarDayCell; - -@interface RDVCalendarMonthView : UIView - -@property (weak) id delegate; - -@property (nonatomic) RDVCalendarDayCell *selectedDayCell; - -- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier; - -- (NSInteger)indexForCell:(RDVCalendarDayCell *)cell; -- (NSInteger)indexForRowAtPoint:(CGPoint)point; -- (RDVCalendarDayCell *)cellForRowAtIndex:(NSInteger)index; -- (NSInteger)indexForSelectedCell; - -- (void)reloadData; - -@end - -@protocol RDVCalendarMonthViewDelegate -- (NSInteger)numberOfWeeksInCalendarMonthView:(RDVCalendarMonthView *)calendarMonthView; -- (NSInteger)numberOfDaysInCalendarMonthView:(RDVCalendarMonthView *)calendarMonthView; -- (NSInteger)numberOfDaysInFirstWeek:(RDVCalendarMonthView *)calendarMonthView; -- (RDVCalendarDayCell *)calendarMonthView:(RDVCalendarMonthView *)calendarMonthView dayCellForIndex:(NSInteger)index; - -@optional -- (BOOL)calendarMonthView:(RDVCalendarMonthView *)calendarMonthView shouldSelectDayCellAtIndex:(NSInteger)index; -- (void)calendarMonthView:(RDVCalendarMonthView *)calendarMonthView willSelectDayCellAtIndex:(NSInteger)index; -- (void)calendarMonthView:(RDVCalendarMonthView *)calendarMonthView didSelectDayCellAtIndex:(NSInteger)index; -@end diff --git a/RDVCalendarView/RDVCalendarMonthView.m b/RDVCalendarView/RDVCalendarMonthView.m deleted file mode 100644 index 3ff4a0a..0000000 --- a/RDVCalendarView/RDVCalendarMonthView.m +++ /dev/null @@ -1,206 +0,0 @@ -// RDVCalendarMonthView.m -// RDVCalendarView -// -// Copyright (c) 2013 Robert Dimitrov -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#import "RDVCalendarMonthView.h" -#import "RDVCalendarDayCell.h" - -@interface RDVCalendarMonthView () - -@property (nonatomic) NSMutableArray *visibleCells; -@property (nonatomic) NSMutableArray *dayCells; - -@property (nonatomic) NSInteger numberOfDays; -@property (nonatomic) NSInteger numberOfWeeks; - -@property (nonatomic) NSInteger firstWeekDays; - -@end - -@implementation RDVCalendarMonthView - -- (id)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - if (self) { - _dayCells = [[NSMutableArray alloc] init]; - _visibleCells = [[NSMutableArray alloc] init]; - } - return self; -} - -- (void)layoutSubviews { - CGSize viewSize = self.frame.size; - - NSInteger column = 7 - [self firstWeekDays]; - CGFloat dayWidth = roundf(viewSize.width / 7) - 1; - NSInteger row = 0; - - for (NSInteger i = 0; i < [self numberOfDays]; i++) { - RDVCalendarDayCell *dayCell = nil; - - if ([[self delegate] respondsToSelector:@selector(calendarMonthView:dayCellForIndex:)]) { - dayCell = [[self delegate] calendarMonthView:self dayCellForIndex:i]; - if (![[self visibleCells] containsObject:dayCell]) { - [[self visibleCells] addObject:dayCell]; - [self addSubview:dayCell]; - } - } - - [dayCell setFrame:CGRectMake(column * (dayWidth + 1), row * (dayWidth + 1), dayWidth, dayWidth)]; - [dayCell setBackgroundColor:[UIColor whiteColor]]; - [dayCell setNeedsLayout]; - - if ([dayCell superview] != self) { - [self addSubview:dayCell]; - } - - if (column == 6) { - column = 0; - row++; - } else { - column++; - } - } -} - -#pragma mark - Methods - -- (void)sizeToFit { - CGRect frame = self.frame; - CGFloat height = CGRectGetMaxY([(UIView *)[[self visibleCells] lastObject] frame]); - - [self setFrame:CGRectMake(CGRectGetMinX(frame), CGRectGetMinY(frame), CGRectGetWidth(frame), height)]; -} - -- (CGSize)sizeThatFits:(CGSize)size { - return CGSizeMake(size.width, size.height); -} - -- (void)reloadData { - for (RDVCalendarDayCell *visibleCell in [self visibleCells]) { - [visibleCell removeFromSuperview]; - [visibleCell prepareForReuse]; - [[self dayCells] addObject:visibleCell]; - } - - [[self visibleCells] removeAllObjects]; - - [self setSelectedDayCell:nil]; - - if ([[self delegate] respondsToSelector:@selector(numberOfWeeksInCalendarMonthView:)]) { - [self setNumberOfWeeks:[[self delegate] numberOfWeeksInCalendarMonthView:self]]; - } - - if ([[self delegate] respondsToSelector:@selector(numberOfDaysInCalendarMonthView:)]) { - [self setNumberOfDays:[[self delegate] numberOfDaysInCalendarMonthView:self]]; - } - - if ([[self delegate] respondsToSelector:@selector(numberOfDaysInFirstWeek:)]) { - [self setFirstWeekDays:[[self delegate] numberOfDaysInFirstWeek:self]]; - } -} - -- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier { - UIView *dayCell = nil; - - if ([[self dayCells] count]) { - dayCell = [[self dayCells] objectAtIndex:0]; - [[self dayCells] removeObjectAtIndex:0]; - } - - return dayCell; -} - -- (NSInteger)indexForCell:(RDVCalendarDayCell *)cell { - return [[self visibleCells] indexOfObject:cell]; -} - -- (NSInteger)indexForRowAtPoint:(CGPoint)point { - RDVCalendarDayCell *cell = [self viewAtLocation:point]; - - if (cell) { - return [self indexForCell:cell]; - } - - return 0; -} - -- (RDVCalendarDayCell *)cellForRowAtIndex:(NSInteger)index { - return [[self visibleCells] objectAtIndex:index]; -} - -- (NSInteger)indexForSelectedCell { - return [self indexForCell:[self selectedDayCell]]; -} - -- (RDVCalendarDayCell *)viewAtLocation:(CGPoint)location { - RDVCalendarDayCell *view = nil; - - for (RDVCalendarDayCell *dayView in [self visibleCells]) { - if (CGRectContainsPoint(dayView.frame, location)) { - view = dayView; - } - } - - return view; -} - -#pragma mark - Touch handling - -- (void)handleTouches:(NSSet *)touches withEvent:(UIEvent *)event { - UITouch *touch = [[event allTouches] anyObject]; - - RDVCalendarDayCell *selectedCell = [self viewAtLocation:[touch locationInView:self]]; - - if (selectedCell && selectedCell != [self selectedDayCell]) { - NSInteger cellIndex = [self indexForCell:selectedCell]; - - if ([[self delegate] respondsToSelector:@selector(calendarMonthView:shouldSelectDayCellAtIndex:)]) { - if (![[self delegate] calendarMonthView:self shouldSelectDayCellAtIndex:cellIndex]) { - return; - } - } - - if ([[self delegate] respondsToSelector:@selector(calendarMonthView:willSelectDayCellAtIndex:)]) { - [[self delegate] calendarMonthView:self willSelectDayCellAtIndex:cellIndex]; - } - - [[self selectedDayCell] setSelected:NO]; - [self setSelectedDayCell:selectedCell]; - [[self selectedDayCell] setSelected:YES]; - - if ([[self delegate] respondsToSelector:@selector(calendarMonthView:didSelectDayCellAtIndex:)]) { - [[self delegate] calendarMonthView:self didSelectDayCellAtIndex:cellIndex]; - } - } -} - -- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { - [self handleTouches:touches withEvent:event]; -} - -- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { - [self handleTouches:touches withEvent:event]; -} - -@end diff --git a/RDVCalendarView/RDVCalendarView.h b/RDVCalendarView/RDVCalendarView.h index 3a275d6..61a5d85 100644 --- a/RDVCalendarView/RDVCalendarView.h +++ b/RDVCalendarView/RDVCalendarView.h @@ -22,18 +22,27 @@ // THE SOFTWARE. #import -#import "RDVCalendarMonthView.h" -#import "RDVCalendarDayCell.h" -#import "RDVCalendarWeekDaysHeader.h" -@class RDVCalendarHeaderView; +@class RDVCalendarDayCell; + +typedef NS_ENUM(NSInteger, RDVCalendarViewDayCellSeparatorType) { + RDVCalendarViewDayCellSeparatorStyleNone, + RDVCalendarViewDayCellSeparatorStyleHorizontal, +}; @protocol RDVCalendarViewDelegate; -@interface RDVCalendarView : UIView +@interface RDVCalendarView : UIView + +#pragma mark - Managing the Delegate +/** + * The object that acts as the delegate of the receiving calendar view. + */ @property (weak) id delegate; +#pragma mark - Configuring a Calendar View + /** * Returns the label, which contains the name of the currently displayed month. (read-only) */ @@ -49,25 +58,123 @@ */ @property (nonatomic, readonly) UIButton *forwardButton; -@property (nonatomic) RDVCalendarWeekDaysHeader *weekDaysView; -@property (nonatomic) RDVCalendarMonthView *monthView; +/** + * Returns array containing the week day labels. + */ +@property (nonatomic, readonly) NSArray *weekDayLabels; +/** + * Returns the height for week day elements. + */ +@property (nonatomic) CGFloat weekDayHeight; + +/** + * The style for separators used between day cells. + */ +@property(nonatomic) RDVCalendarViewDayCellSeparatorType separatorStyle; + +/** + * Returs the color of the current day cell. + */ @property (nonatomic) UIColor *currentDayColor; + +/** + * Returs the color of normal day cell. + */ @property (nonatomic) UIColor *normalDayColor; + +/** + * Returs the color of the selected day cell. + */ @property (nonatomic) UIColor *selectedDayColor; -@property (nonatomic) UIColor *dayTextColor; -@property (nonatomic) UIColor *highlightedDayTextColor; +/** + * The color of separators in the calendar view. + */ +@property(nonatomic, retain) UIColor *separatorColor; +/** + * Returns the currently selected date. + */ @property (nonatomic) NSDate *selectedDate; +/** + * The width of each day cell in the receiver. + */ +@property(nonatomic) CGFloat dayCellWidth; + +/** + * The height of each day cell in the receiver. + */ +@property(nonatomic) CGFloat dayCellHeight; + +#pragma mark - Creating Calendar View Day Cells + +/** + * Registers a class for use in creating new table cells. + */ +- (void)registerClass:(Class)cellClass forCellReuseIdentifier:(NSString *)identifier; + +/** + * Returns a reusable calendar-view day cell object located by its identifier. + */ +- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier; + +#pragma mark - Accessing Cells + +/** + * Returns the table cells that are visible in the receiver. + */ +- (NSArray *)visibleCells; + +- (NSInteger)indexForCell:(RDVCalendarDayCell *)cell; + +- (NSInteger)indexForRowAtPoint:(CGPoint)point; + +- (RDVCalendarDayCell *)dayCellForRowAtIndex:(NSInteger)index; + +#pragma mark - Managing Selections + +/** + * Returns an index identifying the selected day cell. + */ +- (NSInteger)indexForSelectedDayCell; + +/** + * Selects a day cell in the receiver identified by index. + */ +- (void)selectDayCellAtIndex:(NSInteger)index animated:(BOOL)animated; + +/** + * Deselects a given day cell identified by index, with an option to animate the deselection. + */ +- (void)deselectDayCellAtIndex:(NSInteger)index animated:(BOOL)animated; + +#pragma mark - Reloading the Calendar view + +/** + * Reloads the cells of the receiver. + */ - (void)reloadData; @end @protocol RDVCalendarViewDelegate @optional -- (BOOL)calendarView:(RDVCalendarView *)calendarView shouldSelectDate:(NSDate *)date; -- (void)calendarView:(RDVCalendarView *)calendarView willSelectDate:(NSDate *)date; -- (void)calendarView:(RDVCalendarView *)calendarView didSelectDate:(NSDate *)date; +#pragma mark - Managing Selections + +/** + * Asks the delegate if the specified day cell should be selected. + */ +- (BOOL)calendarView:(RDVCalendarView *)calendarView shouldSelectCellAtIndex:(NSInteger)index; + +/** + * Tells the delegate that a specified day cell is about to be selected. + */ +- (void)calendarView:(RDVCalendarView *)calendarView willSelectCellAtIndex:(NSInteger)index; + +/** + * Tells the delegate that the specified row is now selected. + */ +- (void)calendarView:(RDVCalendarView *)calendarView didSelectCellAtIndex:(NSInteger)index; @end diff --git a/RDVCalendarView/RDVCalendarView.m b/RDVCalendarView/RDVCalendarView.m index a5f977d..339d36a 100644 --- a/RDVCalendarView/RDVCalendarView.m +++ b/RDVCalendarView/RDVCalendarView.m @@ -22,15 +22,31 @@ // THE SOFTWARE. #import "RDVCalendarView.h" -#import +#import "RDVCalendarDayCell.h" -@interface RDVCalendarView () +@interface RDVCalendarView () { + NSMutableArray *_visibleCells; + NSMutableArray *_dayCells; + + NSInteger _numberOfDays; + NSInteger _numberOfWeeks; + + NSMutableArray *_separators; + NSMutableArray *_visibleSeparators; + + RDVCalendarDayCell *_selectedDayCell; + + NSArray *_weekDays; +} @property NSDateComponents *selectedDay; @property NSDateComponents *month; @property NSDateComponents *currentDay; @property NSDate *firstDay; +- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier; +- (void)setupWeekDays; + @end @implementation RDVCalendarView @@ -39,12 +55,13 @@ - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { - _normalDayColor = [UIColor whiteColor]; - _selectedDayColor = [UIColor grayColor]; + _dayCells = [[NSMutableArray alloc] initWithCapacity:31]; + _visibleCells = [[NSMutableArray alloc] initWithCapacity:31]; + _currentDayColor = [UIColor lightGrayColor]; + _selectedDayColor = [UIColor grayColor]; - _dayTextColor = [UIColor blackColor]; - _highlightedDayTextColor = [UIColor whiteColor]; + _weekDayHeight = 30.0f; NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar]; @@ -52,7 +69,27 @@ - (id)initWithFrame:(CGRect)frame NSDate *currentDate = [NSDate date]; - [self setupViews]; + _monthLabel = [[UILabel alloc] init]; + [_monthLabel setFont:[UIFont systemFontOfSize:22]]; + [_monthLabel setTextColor:[UIColor blackColor]]; + [_monthLabel setTextAlignment:NSTextAlignmentCenter]; + [self addSubview:_monthLabel]; + + _backButton = [[UIButton alloc] init]; + [_backButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal]; + [_backButton setTitle:@"Prev" forState:UIControlStateNormal]; + [_backButton addTarget:self action:@selector(previousMonthButtonTapped:) + forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:_backButton]; + + _forwardButton = [[UIButton alloc] init]; + [_forwardButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal]; + [_forwardButton setTitle:@"Next" forState:UIControlStateNormal]; + [_forwardButton addTarget:self action:@selector(nextMonthButtonTapped:) + forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:_forwardButton]; + + [self setupWeekDays]; _month = [calendar components:NSYearCalendarUnit| NSMonthCalendarUnit| @@ -69,18 +106,27 @@ - (id)initWithFrame:(CGRect)frame selector:@selector(currentLocaleDidChange:) name:NSCurrentLocaleDidChangeNotification object:nil]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(deviceOrientationDidChange:) + name:UIDeviceOrientationDidChangeNotification + object:nil]; } return self; } +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + - (void)layoutSubviews { CGSize viewSize = self.frame.size; CGSize headerSize = CGSizeMake(viewSize.width, 60.0f); - CGSize previousMonthButtonSize = [[self backButton] sizeThatFits:CGSizeMake(100, 50)]; - CGSize nextMonthButtonSize = [[self forwardButton] sizeThatFits:CGSizeMake(100, 50)]; - CGSize titleSize = [[self monthLabel] sizeThatFits:CGSizeMake(headerSize.width - previousMonthButtonSize.width - - nextMonthButtonSize.width, 50)]; + CGSize previousMonthButtonSize = CGSizeMake([[self backButton] sizeThatFits:CGSizeMake(100, 50)].width, 50); + CGSize nextMonthButtonSize = CGSizeMake([[self forwardButton] sizeThatFits:CGSizeMake(100, 50)].width, 50); + CGSize titleSize = CGSizeMake(viewSize.width - previousMonthButtonSize.width - nextMonthButtonSize.width - 10 - 10, + 50); [[self backButton] setFrame:CGRectMake(10, roundf(headerSize.height / 2 - previousMonthButtonSize.height / 2), previousMonthButtonSize.width, previousMonthButtonSize.height)]; @@ -93,39 +139,100 @@ - (void)layoutSubviews { roundf(headerSize.height / 2 - nextMonthButtonSize.height / 2), nextMonthButtonSize.width, nextMonthButtonSize.height)]; - [[self weekDaysView] setFrame:CGRectMake(0, headerSize.height, viewSize.width, 30)]; + NSInteger column = 0; + CGFloat weekDayWidth = roundf(viewSize.width / [[self weekDayLabels] count]); + for (UILabel *weekDayLabel in [self weekDayLabels]) { + [weekDayLabel setFrame:CGRectMake(column * weekDayWidth, CGRectGetMaxY([[self monthLabel] frame]), weekDayWidth, + [self weekDayHeight])]; + column++; + } + + column = 7 - [self numberOfDaysInFirstWeek]; + CGFloat dayWidth = roundf(viewSize.width / 7) - 1; + NSInteger row = 0; + CGFloat startigCalendarY = CGRectGetMaxY([[self weekDayLabels][0] frame]); - CGSize monthViewSize = [[self monthView] sizeThatFits:CGSizeMake(viewSize.width, viewSize.height - - CGRectGetMaxY([self weekDaysView].frame))]; - [[self monthView] setFrame:CGRectMake(0, CGRectGetMaxY([self weekDaysView].frame), monthViewSize.width, monthViewSize.height)]; + for (NSInteger i = 0; i < [self numberOfDays]; i++) { + RDVCalendarDayCell *dayCell = [self dayCellForIndex:i]; + if (![[self visibleCells] containsObject:dayCell]) { + [_visibleCells addObject:dayCell]; + [self addSubview:dayCell]; + } + + [dayCell setFrame:CGRectMake(column * (dayWidth + 1), startigCalendarY + row * (dayWidth + 1), + dayWidth, dayWidth)]; + [dayCell setNeedsLayout]; + + if ([dayCell superview] != self) { + [self addSubview:dayCell]; + } + + if (column == 6) { + column = 0; + row++; + } else { + column++; + } + } } -- (void)setupViews { - _monthLabel = [[UILabel alloc] init]; - [_monthLabel setFont:[UIFont systemFontOfSize:22]]; - [_monthLabel setTextColor:[UIColor blackColor]]; - [self addSubview:_monthLabel]; +- (void)registerClass:(Class)cellClass forCellReuseIdentifier:(NSString *)identifier { + //TODO implement method +} + +- (void)selectDayCellAtIndex:(NSInteger)index animated:(BOOL)animated { - _backButton = [[UIButton alloc] init]; - [_backButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal]; - [_backButton setTitle:@"Prev" forState:UIControlStateNormal]; - [_backButton addTarget:self action:@selector(previousMonthButtonTapped:) - forControlEvents:UIControlEventTouchUpInside]; - [self addSubview:_backButton]; +} + +- (void)deselectDayCellAtIndex:(NSInteger)index animated:(BOOL)animated { - _forwardButton = [[UIButton alloc] init]; - [_forwardButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal]; - [_forwardButton setTitle:@"Next" forState:UIControlStateNormal]; - [_forwardButton addTarget:self action:@selector(nextMonthButtonTapped:) - forControlEvents:UIControlEventTouchUpInside]; - [self addSubview:_forwardButton]; +} + +- (void)setupWeekDays { + NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar]; + NSInteger firstWeekDay = [calendar firstWeekday] - 1; + + // We need an NSDateFormatter to have access to the localized weekday strings + NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; - _weekDaysView = [[RDVCalendarWeekDaysHeader alloc] init]; - [self addSubview:_weekDaysView]; + NSArray *weekSymbols = [formatter shortWeekdaySymbols]; - _monthView = [[RDVCalendarMonthView alloc] init]; - [_monthView setDelegate:self]; - [self addSubview:_monthView]; + // weekdaySymbols returns and array of strings + NSMutableArray *weekDays = [[NSMutableArray alloc] initWithCapacity:[weekSymbols count]]; + for (NSInteger day = firstWeekDay; day < [weekSymbols count]; day++) { + [weekDays addObject:[weekSymbols objectAtIndex:day]]; + } + + if (firstWeekDay != 0) { + for (NSInteger day = 0; day < firstWeekDay; day++) { + [weekDays addObject:[weekSymbols objectAtIndex:day]]; + } + } + + _weekDays = [NSArray arrayWithArray:weekDays]; + + if (![_weekDayLabels count]) { + NSMutableArray *weekDayLabels = [[NSMutableArray alloc] initWithCapacity:[_weekDays count]]; + + for (NSString *weekDayString in _weekDays) { + UILabel *weekDayLabel = [[UILabel alloc] init]; + [weekDayLabel setFont:[UIFont systemFontOfSize:14]]; + [weekDayLabel setTextColor:[UIColor grayColor]]; + [weekDayLabel setTextAlignment:NSTextAlignmentCenter]; + [weekDayLabel setText:weekDayString]; + [weekDayLabels addObject:weekDayLabel]; + [self addSubview:weekDayLabel]; + } + + _weekDayLabels = [NSArray arrayWithArray:weekDayLabels]; + } else { + NSInteger index = 0; + for (NSString *weekDayString in _weekDays) { + UILabel *weekDayLabel = [self weekDayLabels][index]; + [weekDayLabel setText:weekDayString]; + index++; + } + } } - (void)previousMonthButtonTapped:(id)sender { @@ -145,7 +252,67 @@ - (void)nextMonthButtonTapped:(id)sender { } - (void)reloadData { - [[self monthView] reloadData]; + for (RDVCalendarDayCell *visibleCell in [self visibleCells]) { + [visibleCell removeFromSuperview]; + [visibleCell prepareForReuse]; + [_dayCells addObject:visibleCell]; + } + + [_visibleCells removeAllObjects]; +} + +- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier { + UIView *dayCell = nil; + + for (RDVCalendarDayCell *calendarDayCell in _dayCells) { + if ([[calendarDayCell reuseIdentifier] isEqualToString:identifier]) { + dayCell = calendarDayCell; + break; + } + } + + if (dayCell) { + [_dayCells removeObject:dayCell]; + } + + return dayCell; +} + +- (NSInteger)indexForCell:(RDVCalendarDayCell *)cell { + return [[self visibleCells] indexOfObject:cell]; +} + +- (NSInteger)indexForRowAtPoint:(CGPoint)point { + RDVCalendarDayCell *cell = [self viewAtLocation:point]; + + if (cell) { + return [self indexForCell:cell]; + } + + return 0; +} + +- (RDVCalendarDayCell *)dayCellForRowAtIndex:(NSInteger)index { + return [[self visibleCells] objectAtIndex:index]; +} + +- (NSInteger)indexForSelectedDayCell { + if (_selectedDayCell) { + return [_visibleCells indexOfObject:_selectedDayCell]; + } + return 0; +} + +- (RDVCalendarDayCell *)viewAtLocation:(CGPoint)location { + RDVCalendarDayCell *view = nil; + + for (RDVCalendarDayCell *dayView in [self visibleCells]) { + if (CGRectContainsPoint(dayView.frame, location)) { + view = dayView; + } + } + + return view; } - (void)updateMonthLabelMonth:(NSDateComponents*)month { @@ -158,7 +325,7 @@ - (void)updateMonthLabelMonth:(NSDateComponents*)month { - (void)updateMonthViewMonth:(NSDateComponents *)month { [self setFirstDay:[month.calendar dateFromComponents:month]]; - [[self monthView] reloadData]; + [self reloadData]; } - (void)setSelectedDate:(NSDate *)selectedDate { @@ -197,16 +364,18 @@ - (NSDate *)selectedDate { return [[NSCalendar autoupdatingCurrentCalendar] dateFromComponents:[self selectedDay]]; } +- (NSArray *)visibleCells { + return _visibleCells; +} + #pragma mark - RDVCalendarMonthViewDelegate -- (RDVCalendarDayCell *)calendarMonthView:(RDVCalendarMonthView *)calendarMonthView dayCellForIndex:(NSInteger)index { +- (RDVCalendarDayCell *)dayCellForIndex:(NSInteger)index { static NSString *DayIdentifier = @"Day"; - RDVCalendarDayCell *dayCell = [calendarMonthView dequeueReusableCellWithIdentifier:DayIdentifier]; + RDVCalendarDayCell *dayCell = [self dequeueReusableCellWithIdentifier:DayIdentifier]; if (!dayCell) { dayCell = [[RDVCalendarDayCell alloc] initWithReuseIdentifier:DayIdentifier]; - [[dayCell textLabel] setTextColor:[self dayTextColor]]; - [[dayCell textLabel] setHighlightedTextColor:[self highlightedDayTextColor]]; } [dayCell.textLabel setText:[NSString stringWithFormat:@"%d", index + 1]]; @@ -226,47 +395,124 @@ - (RDVCalendarDayCell *)calendarMonthView:(RDVCalendarMonthView *)calendarMonthV [self month].year == [self selectedDay].year)) { [dayCell setSelected:YES animated:NO]; - [[self monthView] setSelectedDayCell:dayCell]; + _selectedDayCell = dayCell; } return dayCell; } -- (void)calendarMonthView:(RDVCalendarMonthView *)calendarMonthView didSelectDayCellAtIndex:(NSInteger)index { - if (![self selectedDay]) { - [self setSelectedDay:[[NSDateComponents alloc] init]]; - } +- (NSInteger)numberOfWeeks { + return [[[self month] calendar] rangeOfUnit:NSDayCalendarUnit + inUnit:NSWeekCalendarUnit + forDate:[self firstDay]].length; +} + +- (NSInteger)numberOfDays { + return [[[self month] calendar] rangeOfUnit:NSDayCalendarUnit + inUnit:NSMonthCalendarUnit + forDate:[self firstDay]].length; +} + +- (NSInteger)numberOfDaysInFirstWeek { + return [[[self month] calendar] rangeOfUnit:NSDayCalendarUnit + inUnit:NSWeekCalendarUnit + forDate:[self firstDay]].length; +} + +- (void)currentLocaleDidChange:(NSNotification *)notification { + [self setupWeekDays]; + [self updateMonthLabelMonth:[self month]]; +} + +- (void)deviceOrientationDidChange:(NSNotification *)notification { + [self reloadData]; +} + +#pragma mark - Touch handling + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { + UITouch *touch = [[event allTouches] anyObject]; - [[self selectedDay] setMonth:[[self month] month]]; - [[self selectedDay] setYear:[[self month] year]]; - [[self selectedDay] setDay:index + 1]; + CGPoint touchLocation = [touch locationInView:self]; - if ([[self delegate] respondsToSelector:@selector(calendarView:didSelectDate:)]) { - [[self delegate] calendarView:self didSelectDate:[self selectedDate]]; + if (touchLocation.y >= CGRectGetMaxY([[self weekDayLabels][0] frame])) { + RDVCalendarDayCell *selectedDayCell = [self viewAtLocation:touchLocation]; + + if (selectedDayCell && selectedDayCell != _selectedDayCell) { + NSInteger cellIndex = [self indexForCell:selectedDayCell]; + + if ([[self delegate] respondsToSelector:@selector(calendarView:shouldSelectCellAtIndex:)]) { + if (![[self delegate] calendarView:self shouldSelectCellAtIndex:cellIndex]) { + return; + } + } + + [_selectedDayCell setSelected:NO]; + _selectedDayCell = selectedDayCell; + [_selectedDayCell setHighlighted:YES]; + } } } -- (NSInteger)numberOfWeeksInCalendarMonthView:(RDVCalendarMonthView *)calendarMonthView { - return [self.month.calendar rangeOfUnit:NSDayCalendarUnit - inUnit:NSWeekCalendarUnit - forDate:[self firstDay]].length; -} - -- (NSInteger)numberOfDaysInCalendarMonthView:(RDVCalendarMonthView *)calendarMonthView { - return [self.month.calendar rangeOfUnit:NSDayCalendarUnit - inUnit:NSMonthCalendarUnit - forDate:[self firstDay]].length; +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { + UITouch *touch = [[event allTouches] anyObject]; + + CGPoint touchLocation = [touch locationInView:self]; + + if (touchLocation.y >= CGRectGetMaxY([[self weekDayLabels][0] frame])) { + RDVCalendarDayCell *selectedDayCell = [self viewAtLocation:touchLocation]; + + if (selectedDayCell != _selectedDayCell) { + if ([_selectedDayCell isSelected]) { + [_selectedDayCell setSelected:NO]; + } else { + [_selectedDayCell setHighlighted:NO]; + } + + _selectedDayCell = nil; + } + } else if ([_selectedDayCell isHighlighted]) { + [_selectedDayCell setHighlighted:NO]; + _selectedDayCell = nil; + } } -- (NSInteger)numberOfDaysInFirstWeek:(RDVCalendarMonthView *)calendarMonthView { - return [self.month.calendar rangeOfUnit:NSDayCalendarUnit - inUnit:NSWeekCalendarUnit - forDate:[self firstDay]].length; +- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { + if ([_selectedDayCell isHighlighted]) { + [_selectedDayCell setHighlighted:NO]; + _selectedDayCell = nil; + } } -- (void)currentLocaleDidChange:(NSNotification *)notification { - [[self weekDaysView] setupWeekDays]; - [self updateMonthLabelMonth:[self month]]; +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + UITouch *touch = [[event allTouches] anyObject]; + + RDVCalendarDayCell *selectedDayCell = [self viewAtLocation:[touch locationInView:self]]; + + if (selectedDayCell == _selectedDayCell) { + NSInteger cellIndex = [self indexForCell:selectedDayCell]; + + if ([[self delegate] respondsToSelector:@selector(calendarView:willSelectCellAtIndex:)]) { + [[self delegate] calendarView:self willSelectCellAtIndex:cellIndex]; + } + + [_selectedDayCell setSelected:YES]; + + if (![self selectedDay]) { + [self setSelectedDay:[[NSDateComponents alloc] init]]; + } + + [[self selectedDay] setMonth:[[self month] month]]; + [[self selectedDay] setYear:[[self month] year]]; + [[self selectedDay] setDay:cellIndex + 1]; + + if ([[self delegate] respondsToSelector:@selector(calendarView:didSelectCellAtIndex:)]) { + [[self delegate] calendarView:self didSelectCellAtIndex:cellIndex]; + } + } else { + [_selectedDayCell setSelected:NO]; + _selectedDayCell = nil; + } } @end diff --git a/RDVCalendarView/RDVCalendarViewController.h b/RDVCalendarView/RDVCalendarViewController.h index 3b38e9e..4b2d20c 100644 --- a/RDVCalendarView/RDVCalendarViewController.h +++ b/RDVCalendarView/RDVCalendarViewController.h @@ -26,7 +26,14 @@ @interface RDVCalendarViewController : UIViewController -@property (nonatomic) RDVCalendarView *calendarView; +/** + * Returns the calendar view managed by the controller object. + */ +@property (nonatomic, strong) RDVCalendarView *calendarView; + +/** + * A Boolean value indicating if the controller clears the selection when the calendar appears. + */ @property (nonatomic) BOOL clearsSelectionOnViewWillAppear; @end diff --git a/RDVCalendarView/RDVCalendarViewController.m b/RDVCalendarView/RDVCalendarViewController.m index 62504e6..0a62f70 100644 --- a/RDVCalendarView/RDVCalendarViewController.m +++ b/RDVCalendarView/RDVCalendarViewController.m @@ -37,17 +37,12 @@ - (void)loadView { self.view = _calendarView; } -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation { - if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) { - return YES; - } - return toInterfaceOrientation == UIInterfaceOrientationPortrait; -} - -#pragma mark - RDVCalendarViewDelegate - -- (void)calendarView:(RDVCalendarView *)calendarView didSelectDate:(NSDate *)date { +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + if ([self clearsSelectionOnViewWillAppear]) { + [[self calendarView] deselectDayCellAtIndex:[[self calendarView] indexForSelectedDayCell] animated:YES]; + } } @end diff --git a/RDVCalendarView/RDVCalendarWeekDaysHeader.h b/RDVCalendarView/RDVCalendarWeekDaysHeader.h deleted file mode 100644 index 4b95a68..0000000 --- a/RDVCalendarView/RDVCalendarWeekDaysHeader.h +++ /dev/null @@ -1,33 +0,0 @@ -// RDVCalendarWeekDaysHeader.h -// RDVCalendarView -// -// Copyright (c) 2013 Robert Dimitrov -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#import - -@interface RDVCalendarWeekDaysHeader : UIView - -@property (nonatomic) NSArray *weekDays; -@property (nonatomic) NSDictionary *weekDayAttributes; - -- (void)setupWeekDays; - -@end diff --git a/RDVCalendarView/RDVCalendarWeekDaysHeader.m b/RDVCalendarView/RDVCalendarWeekDaysHeader.m deleted file mode 100644 index 82507eb..0000000 --- a/RDVCalendarView/RDVCalendarWeekDaysHeader.m +++ /dev/null @@ -1,102 +0,0 @@ -// RDVCalendarWeekDaysHeader.m -// RDVCalendarView -// -// Copyright (c) 2013 Robert Dimitrov -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#import "RDVCalendarWeekDaysHeader.h" - -@implementation RDVCalendarWeekDaysHeader - -- (id)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - if (self) { - [self setBackgroundColor:[UIColor whiteColor]]; - - [self setupWeekDays]; - - _weekDayAttributes = @{UITextAttributeFont: [UIFont systemFontOfSize:14], - UITextAttributeTextColor: [UIColor grayColor], - UITextAttributeTextShadowColor: [UIColor clearColor], - UITextAttributeTextShadowOffset: [NSValue valueWithUIOffset:UIOffsetZero], - }; - } - return self; -} - -- (void)drawRect:(CGRect)rect { - CGSize viewSize = self.frame.size; - - NSInteger column = 0; - CGFloat elementWidth = roundf(viewSize.width / [[self weekDays] count]); - - CGContextRef context = UIGraphicsGetCurrentContext(); - CGContextSaveGState(context); - - UIOffset titleShadowOffset = [self.weekDayAttributes[UITextAttributeTextShadowOffset] UIOffsetValue]; - - CGContextSetFillColorWithColor(context, [self.weekDayAttributes[UITextAttributeTextColor] CGColor]); - CGContextSetShadowWithColor(context, CGSizeMake(titleShadowOffset.horizontal, titleShadowOffset.vertical), - 1.0, [self.weekDayAttributes[UITextAttributeTextShadowColor] CGColor]); - - for (NSString *weekDayString in [self weekDays]) { - CGSize titleSize = [weekDayString sizeWithFont:self.weekDayAttributes[UITextAttributeFont] - constrainedToSize:CGSizeMake(elementWidth, viewSize.height)]; - - [weekDayString drawInRect:CGRectMake(roundf(elementWidth / 2 - titleSize.width / 2) + column * elementWidth, - roundf(viewSize.height / 2 - titleSize.height / 2), - titleSize.width, titleSize.height) - withFont:self.weekDayAttributes[UITextAttributeFont] - lineBreakMode:NSLineBreakByTruncatingTail]; - - column++; - } - - CGContextRestoreGState(context); -} - -- (void)setupWeekDays { - NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar]; - NSInteger firstWeekDay = [calendar firstWeekday] - 1; - - // We need an NSDateFormatter to have access to the localized weekday strings - NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; - - NSArray *weekSymbols = [formatter shortWeekdaySymbols]; - - // weekdaySymbols returns and array of strings - NSMutableArray *weekDays = [[NSMutableArray alloc] initWithCapacity:[weekSymbols count]]; - for (NSInteger day = firstWeekDay; day < [weekSymbols count]; day++) { - [weekDays addObject:[weekSymbols objectAtIndex:day]]; - } - - if (firstWeekDay != 0) { - for (NSInteger day = 0; day < firstWeekDay; day++) { - [weekDays addObject:[weekSymbols objectAtIndex:day]]; - } - } - - _weekDays = [NSArray arrayWithArray:weekDays]; - - [self setNeedsDisplay]; -} - -@end diff --git a/README.md b/README.md index 77ba181..6b442ce 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,11 @@ Under development +## Features + +* iPad and iPhone support +* Calendar view implemented on the principle of UITableView + ## Roadmap * Day separator with customizable color