diff --git a/Examples/Calendar.xcodeproj/project.pbxproj b/Examples/Calendar.xcodeproj/project.pbxproj index 40aab67..0585cf0 100644 --- a/Examples/Calendar.xcodeproj/project.pbxproj +++ b/Examples/Calendar.xcodeproj/project.pbxproj @@ -20,6 +20,8 @@ 1D2391395A8710F3E85A8A /* left_arrow@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1D2391395A8710F3E85A89 /* left_arrow@2x.png */; }; 1D2391395A8710F3E85A8C /* right_arrow.png in Resources */ = {isa = PBXBuildFile; fileRef = 1D2391395A8710F3E85A8B /* right_arrow.png */; }; 1D2391395A8710F3E85A8E /* right_arrow@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1D2391395A8710F3E85A8D /* right_arrow@2x.png */; }; + 96D75AF818FF288500498AD7 /* HCTwoWeekCalendarView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 96D75AF718FF288500498AD7 /* HCTwoWeekCalendarView.xib */; }; + 96D75AFB18FF31A900498AD7 /* HCPTwoWeekCalendarViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 96D75AFA18FF31A900498AD7 /* HCPTwoWeekCalendarViewController.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -42,6 +44,9 @@ 1D2391395A8710F3E85A89 /* left_arrow@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "left_arrow@2x.png"; path = "../../Source/resources/left_arrow@2x.png"; sourceTree = ""; }; 1D2391395A8710F3E85A8B /* right_arrow.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = right_arrow.png; path = ../../Source/resources/right_arrow.png; sourceTree = ""; }; 1D2391395A8710F3E85A8D /* right_arrow@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "right_arrow@2x.png"; path = "../../Source/resources/right_arrow@2x.png"; sourceTree = ""; }; + 96D75AF718FF288500498AD7 /* HCTwoWeekCalendarView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = HCTwoWeekCalendarView.xib; sourceTree = ""; }; + 96D75AF918FF31A900498AD7 /* HCPTwoWeekCalendarViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HCPTwoWeekCalendarViewController.h; sourceTree = ""; }; + 96D75AFA18FF31A900498AD7 /* HCPTwoWeekCalendarViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HCPTwoWeekCalendarViewController.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -96,6 +101,9 @@ 1D2391395A8710F3E85A66 /* CKViewController.h */, 1D2391395A8710F3E85A64 /* CKAppDelegate.m */, 1D2391395A8710F3E85A63 /* CKAppDelegate.h */, + 96D75AF918FF31A900498AD7 /* HCPTwoWeekCalendarViewController.h */, + 96D75AFA18FF31A900498AD7 /* HCPTwoWeekCalendarViewController.m */, + 96D75AF718FF288500498AD7 /* HCTwoWeekCalendarView.xib */, 1D2391395A8710F3E85A5B /* Supporting Files */, 1D2391395A8710F3E85A86 /* resources */, ); @@ -149,6 +157,8 @@ /* Begin PBXProject section */ 001D2391395A8710F3E85A45 /* Project object */ = { isa = PBXProject; + attributes = { + }; buildConfigurationList = 1D2391395A8710F3E85A46 /* Build configuration list for PBXProject "Calendar" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; @@ -175,6 +185,7 @@ 1D2391395A8710F3E85A88 /* left_arrow.png in Resources */, 1D2391395A8710F3E85A8A /* left_arrow@2x.png in Resources */, 1D2391395A8710F3E85A8C /* right_arrow.png in Resources */, + 96D75AF818FF288500498AD7 /* HCTwoWeekCalendarView.xib in Resources */, 1D2391395A8710F3E85A8E /* right_arrow@2x.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -190,6 +201,7 @@ 1D2391395A8710F3E85A65 /* CKAppDelegate.m in Sources */, 1D2391395A8710F3E85A68 /* CKViewController.m in Sources */, 1D2391395A8710F3E85A85 /* CKCalendarView.m in Sources */, + 96D75AFB18FF31A900498AD7 /* HCPTwoWeekCalendarViewController.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -260,6 +272,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Calendar/Calendar-Prefix.pch"; INFOPLIST_FILE = "Calendar/Calendar-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 7.0; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; @@ -271,6 +284,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Calendar/Calendar-Prefix.pch"; INFOPLIST_FILE = "Calendar/Calendar-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 7.0; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; @@ -295,6 +309,7 @@ 1D2391395A8710F3E85A4F /* Debug */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/Examples/Calendar/CKAppDelegate.m b/Examples/Calendar/CKAppDelegate.m index cab4e14..6dc7dba 100644 --- a/Examples/Calendar/CKAppDelegate.m +++ b/Examples/Calendar/CKAppDelegate.m @@ -12,8 +12,10 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // Override point for customization after application launch. + self.viewController = [[CKViewController alloc] init]; - self.window.rootViewController = self.viewController; + UINavigationController *navCtrl = [[UINavigationController alloc] initWithRootViewController:self.viewController]; + self.window.rootViewController = navCtrl; [self.window makeKeyAndVisible]; return YES; } diff --git a/Examples/Calendar/CKViewController.m b/Examples/Calendar/CKViewController.m index 9d50374..39d4a1b 100644 --- a/Examples/Calendar/CKViewController.m +++ b/Examples/Calendar/CKViewController.m @@ -1,50 +1,106 @@ #import #import "CKViewController.h" #import "CKCalendarView.h" +#import "HCPTwoWeekCalendarViewController.h" @interface CKViewController () -@property(nonatomic, weak) CKCalendarView *calendar; -@property(nonatomic, strong) UILabel *dateLabel; +@property(nonatomic, weak) CKCalendarView *nonFlatCalendar; +@property(nonatomic, weak) CKCalendarView *flatCalendar; +@property(nonatomic, strong) UILabel *dateLabelFlat; +@property(nonatomic, strong) UILabel *dateLabelNonFlat; @property(nonatomic, strong) NSDateFormatter *dateFormatter; @property(nonatomic, strong) NSDate *minimumDate; -@property(nonatomic, strong) NSArray *disabledDates; +@property(nonatomic, strong) NSDate *disabledDate; +@property(nonatomic, strong) UIScrollView *scrollView; @end @implementation CKViewController + - (id)init { self = [super init]; if (self) { - CKCalendarView *calendar = [[CKCalendarView alloc] initWithStartDay:startMonday]; - self.calendar = calendar; - calendar.delegate = self; - - self.dateFormatter = [[NSDateFormatter alloc] init]; - [self.dateFormatter setDateFormat:@"dd/MM/yyyy"]; - self.minimumDate = [self.dateFormatter dateFromString:@"20/09/2012"]; - - self.disabledDates = @[ - [self.dateFormatter dateFromString:@"05/01/2013"], - [self.dateFormatter dateFromString:@"06/01/2013"], - [self.dateFormatter dateFromString:@"07/01/2013"] - ]; - - calendar.onlyShowCurrentMonth = NO; - calendar.adaptHeightToNumberOfWeeksInMonth = YES; + self.scrollView = [[UIScrollView alloc] initWithFrame:self.view.frame]; + self.scrollView.scrollEnabled = YES; + self.scrollView.contentSize = CGSizeMake(320, 800); + + [self addNonFlatDesignCalendar:CGRectMake(10, 44, 300, 320)]; + [self addFlatDesignCalendar:CGRectMake(10, 420, 300, 320)]; + + [self addButtonToGotoTwoWeekViewController:CGRectMake(10, 720, 200, 22)]; + + [self.view addSubview:self.scrollView]; + } + return self; +} - calendar.frame = CGRectMake(10, 10, 300, 320); - [self.view addSubview:calendar]; +- (void)addButtonToGotoTwoWeekViewController:(CGRect)rect +{ + UIButton *button = [[UIButton alloc] initWithFrame:rect]; + + [button setTitle:@"Goto" forState:UIControlStateNormal]; + button.backgroundColor = [UIColor redColor]; + + [button addTarget:self action:@selector(gotoTwoWeekViewClicked:) forControlEvents:UIControlEventTouchUpInside]; + [self.scrollView addSubview:button]; +} - self.dateLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, CGRectGetMaxY(calendar.frame) + 4, self.view.bounds.size.width, 24)]; - [self.view addSubview:self.dateLabel]; +- (void)gotoTwoWeekViewClicked:(id)sender +{ + UIViewController *viewController = [[HCPTwoWeekCalendarViewController alloc] init]; + [self.navigationController pushViewController:viewController animated:YES]; +} - self.view.backgroundColor = [UIColor whiteColor]; +- (void)addNonFlatDesignCalendar:(CGRect)rect { + CKCalendarView *calendar = [[CKCalendarView alloc] initWithStartDay:startMonday]; + self.nonFlatCalendar = calendar; + self.nonFlatCalendar.delegate = self; + + self.dateFormatter = [[NSDateFormatter alloc] init]; + [self.dateFormatter setDateFormat:@"dd/MM/yyyy"]; + self.minimumDate = [self.dateFormatter dateFromString:@"20/09/2012"]; + + self.disabledDate = [self.dateFormatter dateFromString:@"05/01/2014"]; + + calendar.onlyShowCurrentMonth = NO; + calendar.adaptHeightToNumberOfWeeksInMonth = YES; + + calendar.frame = rect; + [self.scrollView addSubview:calendar]; + + self.dateLabelNonFlat = [[UILabel alloc] initWithFrame:CGRectMake(10, CGRectGetMaxY(calendar.frame), self.view.bounds.size.width, 24)]; + [self.scrollView addSubview:self.dateLabelNonFlat]; + + self.view.backgroundColor = [UIColor whiteColor]; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(localeDidChange) name:NSCurrentLocaleDidChangeNotification object:nil]; +} - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(localeDidChange) name:NSCurrentLocaleDidChangeNotification object:nil]; - } - return self; +- (void)addFlatDesignCalendar:(CGRect)rect { + CKCalendarView *calendar = [[CKCalendarView alloc] initWithStartDay:startMonday style:CKCalendarStyleFlat]; + self.flatCalendar = calendar; + self.flatCalendar.delegate = self; + + self.dateFormatter = [[NSDateFormatter alloc] init]; + [self.dateFormatter setDateFormat:@"dd/MM/yyyy"]; + self.minimumDate = [self.dateFormatter dateFromString:@"20/09/2012"]; + + self.disabledDate = [self.dateFormatter dateFromString:@"01/05/2014"], + + calendar.onlyShowCurrentMonth = NO; + calendar.adaptHeightToNumberOfWeeksInMonth = YES; + + calendar.frame = rect; + [self.scrollView addSubview:calendar]; + + self.dateLabelFlat = [[UILabel alloc] initWithFrame:CGRectMake(10, CGRectGetMaxY(calendar.frame), self.view.bounds.size.width, 24)]; + [self.scrollView addSubview:self.dateLabelFlat]; + + self.view.backgroundColor = [UIColor whiteColor]; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(localeDidChange) name:NSCurrentLocaleDidChangeNotification object:nil]; } - (void)dealloc { @@ -73,14 +129,13 @@ - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interface } - (void)localeDidChange { - [self.calendar setLocale:[NSLocale currentLocale]]; + [self.flatCalendar setLocale:[NSLocale currentLocale]]; + [self.nonFlatCalendar setLocale:[NSLocale currentLocale]]; } - (BOOL)dateIsDisabled:(NSDate *)date { - for (NSDate *disabledDate in self.disabledDates) { - if ([disabledDate isEqualToDate:date]) { - return YES; - } + if ([self.disabledDate isEqualToDate:date]) { + return YES; } return NO; } @@ -101,15 +156,20 @@ - (BOOL)calendar:(CKCalendarView *)calendar willSelectDate:(NSDate *)date { } - (void)calendar:(CKCalendarView *)calendar didSelectDate:(NSDate *)date { - self.dateLabel.text = [self.dateFormatter stringFromDate:date]; + if (calendar == self.flatCalendar) { + self.dateLabelFlat.text = [self.dateFormatter stringFromDate:date]; + } else { + self.dateLabelNonFlat.text = [self.dateFormatter stringFromDate:date]; + } + } - (BOOL)calendar:(CKCalendarView *)calendar willChangeToMonth:(NSDate *)date { if ([date laterDate:self.minimumDate] == date) { - self.calendar.backgroundColor = [UIColor blueColor]; + calendar.backgroundColor = [UIColor blueColor]; return YES; } else { - self.calendar.backgroundColor = [UIColor redColor]; + calendar.backgroundColor = [UIColor redColor]; return NO; } } diff --git a/Examples/Calendar/HCPTwoWeekCalendarViewController.h b/Examples/Calendar/HCPTwoWeekCalendarViewController.h new file mode 100644 index 0000000..f2114f7 --- /dev/null +++ b/Examples/Calendar/HCPTwoWeekCalendarViewController.h @@ -0,0 +1,13 @@ +// +// HCPTwoWeekCalendarViewController.h +// Calendar +// +// Created by Adam Perry-Pelletier on 4/16/14. +// +// + +#import + +@interface HCPTwoWeekCalendarViewController : UIViewController + +@end diff --git a/Examples/Calendar/HCPTwoWeekCalendarViewController.m b/Examples/Calendar/HCPTwoWeekCalendarViewController.m new file mode 100644 index 0000000..4958832 --- /dev/null +++ b/Examples/Calendar/HCPTwoWeekCalendarViewController.m @@ -0,0 +1,72 @@ +// +// HCPTwoWeekCalendarViewController.m +// Calendar +// +// Created by Adam Perry-Pelletier on 4/16/14. +// +// + +#import "HCPTwoWeekCalendarViewController.h" +#import "CKCalendarView.h" + +@interface HCPTwoWeekCalendarViewController () + +@property(nonatomic, strong) NSDateFormatter *dateFormatter; + +@end + +@implementation HCPTwoWeekCalendarViewController + +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + } + return self; +} + + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + self.view.backgroundColor = [UIColor whiteColor]; + [self addTwoWeekCalendarView:CGRectMake(0,100,320,112)]; +} + +- (void)addTwoWeekCalendarView:(CGRect)rect { + NSArray *array = [[NSBundle mainBundle] loadNibNamed:@"HCTwoWeekCalendarView" owner:nil options:nil]; + UIView *calendarView = [array lastObject]; + calendarView.frame = CGRectMake(0, rect.origin.y, calendarView.frame.size.width, calendarView.frame.size.height); + UIScrollView *innerCalendarView = (UIScrollView *)[calendarView viewWithTag:1]; + + CKCalendarView *calendar = [[CKCalendarView alloc] initWithStartDay:startMonday + style:CKCalendarStyleFlat + suppressHeader:YES + suppressDayLabels:YES]; + + self.dateFormatter = [[NSDateFormatter alloc] init]; + [self.dateFormatter setDateFormat:@"dd/MM/yyyy"]; + + calendar.onlyShowCurrentMonth = NO; + calendar.adaptHeightToNumberOfWeeksInMonth = YES; + + [innerCalendarView addSubview:calendar]; + innerCalendarView.contentSize = calendar.frame.size; + + [self.view addSubview:calendarView]; +} + + +/* +#pragma mark - Navigation + +// In a storyboard-based application, you will often want to do a little preparation before navigation +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender +{ + // Get the new view controller using [segue destinationViewController]. + // Pass the selected object to the new view controller. +} +*/ + +@end diff --git a/Examples/Calendar/HCTwoWeekCalendarView.xib b/Examples/Calendar/HCTwoWeekCalendarView.xib new file mode 100644 index 0000000..1caad10 --- /dev/null +++ b/Examples/Calendar/HCTwoWeekCalendarView.xib @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/CKCalendarView.h b/Source/CKCalendarView.h index 4615c5a..e149ef5 100644 --- a/Source/CKCalendarView.h +++ b/Source/CKCalendarView.h @@ -31,10 +31,17 @@ typedef enum { startMonday = 2, } CKCalendarStartDay; +typedef enum : NSInteger { + CKCalendarStyleSkeuomorphic, + CKCalendarStyleFlat +} CKCalendarStyle; + @interface CKCalendarView : UIView - (id)initWithStartDay:(CKCalendarStartDay)firstDay; -- (id)initWithStartDay:(CKCalendarStartDay)firstDay frame:(CGRect)frame; +- (id)initWithStartDay:(CKCalendarStartDay)firstDay style:(CKCalendarStyle)style; +- (id)initWithStartDay:(CKCalendarStartDay)firstDay frame:(CGRect)frame style:(CKCalendarStyle)style; +- (id)initWithStartDay:(CKCalendarStartDay)firstDay style:(CKCalendarStyle)style suppressHeader:(BOOL)suppressHeader suppressDayLabels:(BOOL)supressDayLabels; @property (nonatomic) CKCalendarStartDay calendarStartDay; @property (nonatomic, strong) NSLocale *locale; @@ -52,6 +59,7 @@ typedef enum { @property (nonatomic, strong) UIFont *dateOfWeekFont; @property (nonatomic, strong) UIColor *dayOfWeekTextColor; @property (nonatomic, strong) UIFont *dateFont; +@property (nonatomic, strong) UIColor *outOfMonthBackgroundColor; - (void)setMonthButtonColor:(UIColor *)color; - (void)setInnerBorderColor:(UIColor *)color; diff --git a/Source/CKCalendarView.m b/Source/CKCalendarView.m index e79e5ac..3c4fa19 100644 --- a/Source/CKCalendarView.m +++ b/Source/CKCalendarView.m @@ -21,11 +21,13 @@ #import "CKCalendarView.h" #define BUTTON_MARGIN 4 -#define CALENDAR_MARGIN 5 +#define CALENDAR_MARGIN_SKEW 5 +#define CALENDAR_MARGIN_FLAT 0 #define TOP_HEIGHT 44 #define DAYS_HEADER_HEIGHT 22 #define DEFAULT_CELL_WIDTH 43 #define CELL_BORDER_WIDTH 1 +#define SMALLER_INNER_RADIUS_FACTOR 2.0f; #define UIColorFromRGB(rgbValue) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 green:((float)((rgbValue & 0xFF00) >> 8))/255.0 blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0] @@ -109,7 +111,7 @@ @interface CKCalendarView () @property(nonatomic, strong) UIButton *prevButton; @property(nonatomic, strong) UIButton *nextButton; @property(nonatomic, strong) UIView *calendarContainer; -@property(nonatomic, strong) GradientView *daysHeader; +@property(nonatomic, strong) UIView *daysHeader; @property(nonatomic, strong) NSArray *dayOfWeekLabels; @property(nonatomic, strong) NSMutableArray *dateButtons; @property(nonatomic, strong) NSDateFormatter *dateFormatter; @@ -119,6 +121,15 @@ @interface CKCalendarView () @property (nonatomic, strong) NSCalendar *calendar; @property(nonatomic, assign) CGFloat cellWidth; +// style affecting properties +@property (nonatomic, assign) CKCalendarStyle style; +@property (nonatomic, assign) NSInteger calendarMargin; +@property (nonatomic, assign) CGFloat cornerRadius; + +// supress various components +@property (nonatomic, assign) BOOL suppressHeader; +@property (nonatomic, assign) BOOL suppressDayLabels; + @end @implementation CKCalendarView @@ -126,14 +137,77 @@ @implementation CKCalendarView @dynamic locale; - (id)init { - return [self initWithStartDay:startSunday]; + return [self initWithStartDay:startSunday + style:CKCalendarStyleSkeuomorphic + frame:CGRectMake(0, 0, 320, 320) + suppressHeader:NO + suppressDayLabels:NO]; } + - (id)initWithStartDay:(CKCalendarStartDay)firstDay { - return [self initWithStartDay:firstDay frame:CGRectMake(0, 0, 320, 320)]; + + return [self initWithStartDay:firstDay + style:CKCalendarStyleSkeuomorphic + frame:CGRectMake(0, 0, 320, 320) + suppressHeader:NO + suppressDayLabels:NO] ; + +} + +- (id)initWithStartDay:(CKCalendarStartDay)firstDay + style:(CKCalendarStyle)style + suppressHeader:(BOOL)suppressHeader + suppressDayLabels:(BOOL)supressDayLabels +{ + + return [self initWithStartDay:firstDay + style:style + frame:CGRectMake(0, 0, 320, 320) + suppressHeader:suppressHeader + suppressDayLabels:supressDayLabels] ; + +} + +- (id)initWithStartDay:(CKCalendarStartDay)firstDay frame:(CGRect)frame style:(CKCalendarStyle)style +{ + return [self initWithStartDay:firstDay style:style frame:frame suppressHeader:NO suppressDayLabels:NO]; +} + +- (id)initWithStartDay:(CKCalendarStartDay)firstDay + style:(CKCalendarStyle)style +{ + + return [self initWithStartDay:firstDay + style:style + frame:CGRectMake(0, 0, 320, 320) + suppressHeader:NO + suppressDayLabels:NO]; + +} + +- (id)initWithStartDay:(CKCalendarStartDay)firstDay + style:(CKCalendarStyle)style + frame:(CGRect)frame + suppressHeader:(BOOL)suppressHeader + suppressDayLabels:(BOOL)supressDayLabels +{ + + self = [super initWithFrame:frame]; + if (self) { + self.cornerRadius = [self cornerRadiusForStyle:style]; + self.suppressHeader = suppressHeader; + self.suppressDayLabels = supressDayLabels; + [self _init:firstDay style:style]; + } + return self; + } -- (void)_init:(CKCalendarStartDay)firstDay { +- (void)_init:(CKCalendarStartDay)firstDay style:(CKCalendarStyle)style{ + self.style = style; + self.calendarMargin = [self calendarMarginForStyle:style]; + self.calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; [self.calendar setLocale:[NSLocale currentLocale]]; @@ -146,64 +220,29 @@ - (void)_init:(CKCalendarStartDay)firstDay { self.calendarStartDay = firstDay; self.onlyShowCurrentMonth = YES; self.adaptHeightToNumberOfWeeksInMonth = YES; + self.outOfMonthBackgroundColor = UIColorFromRGB(0xE6E6E6); - self.layer.cornerRadius = 6.0f; + self.layer.cornerRadius = self.cornerRadius; UIView *highlight = [[UIView alloc] initWithFrame:CGRectZero]; highlight.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.2]; - highlight.layer.cornerRadius = 6.0f; + highlight.layer.cornerRadius = self.cornerRadius; [self addSubview:highlight]; self.highlight = highlight; - // SET UP THE HEADER - UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectZero]; - titleLabel.textAlignment = NSTextAlignmentCenter; - titleLabel.backgroundColor = [UIColor clearColor]; - titleLabel.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleWidth; - [self addSubview:titleLabel]; - self.titleLabel = titleLabel; - - UIButton *prevButton = [UIButton buttonWithType:UIButtonTypeCustom]; - [prevButton setImage:[UIImage imageNamed:@"left_arrow.png"] forState:UIControlStateNormal]; - prevButton.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin; - [prevButton addTarget:self action:@selector(_moveCalendarToPreviousMonth) forControlEvents:UIControlEventTouchUpInside]; - [self addSubview:prevButton]; - self.prevButton = prevButton; - - UIButton *nextButton = [UIButton buttonWithType:UIButtonTypeCustom]; - [nextButton setImage:[UIImage imageNamed:@"right_arrow.png"] forState:UIControlStateNormal]; - nextButton.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleLeftMargin; - [nextButton addTarget:self action:@selector(_moveCalendarToNextMonth) forControlEvents:UIControlEventTouchUpInside]; - [self addSubview:nextButton]; - self.nextButton = nextButton; + [self setUpHeader]; // THE CALENDAR ITSELF UIView *calendarContainer = [[UIView alloc] initWithFrame:CGRectZero]; calendarContainer.layer.borderWidth = 1.0f; calendarContainer.layer.borderColor = [UIColor blackColor].CGColor; calendarContainer.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth; - calendarContainer.layer.cornerRadius = 4.0f; + calendarContainer.layer.cornerRadius = self.cornerRadius - SMALLER_INNER_RADIUS_FACTOR; calendarContainer.clipsToBounds = YES; [self addSubview:calendarContainer]; self.calendarContainer = calendarContainer; - GradientView *daysHeader = [[GradientView alloc] initWithFrame:CGRectZero]; - daysHeader.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleWidth; - [self.calendarContainer addSubview:daysHeader]; - self.daysHeader = daysHeader; - - NSMutableArray *labels = [NSMutableArray array]; - for (int i = 0; i < 7; ++i) { - UILabel *dayOfWeekLabel = [[UILabel alloc] initWithFrame:CGRectZero]; - dayOfWeekLabel.textAlignment = NSTextAlignmentCenter; - dayOfWeekLabel.backgroundColor = [UIColor clearColor]; - dayOfWeekLabel.shadowColor = [UIColor whiteColor]; - dayOfWeekLabel.shadowOffset = CGSizeMake(0, 1); - [labels addObject:dayOfWeekLabel]; - [self.calendarContainer addSubview:dayOfWeekLabel]; - } - self.dayOfWeekLabels = labels; - [self _updateDayOfWeekLabels]; + [self setupDayOfWeekLabels]; // at most we'll need 42 buttons, so let's just bite the bullet and make them now... NSMutableArray *dateButtons = [NSMutableArray array]; @@ -217,27 +256,69 @@ - (void)_init:(CKCalendarStartDay)firstDay { // initialize the thing self.monthShowing = [NSDate date]; - [self _setDefaultStyle]; + [self _setDefaultStyle:style]; [self layoutSubviews]; // TODO: this is a hack to get the first month to show properly } -- (id)initWithStartDay:(CKCalendarStartDay)firstDay frame:(CGRect)frame { - self = [super initWithFrame:frame]; - if (self) { - [self _init:firstDay]; +- (void)setUpHeader +{ + if (!self.suppressHeader) { + UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + titleLabel.textAlignment = NSTextAlignmentCenter; + titleLabel.backgroundColor = [UIColor clearColor]; + titleLabel.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleWidth; + [self addSubview:titleLabel]; + self.titleLabel = titleLabel; + + UIButton *prevButton = [UIButton buttonWithType:UIButtonTypeCustom]; + [prevButton setImage:[UIImage imageNamed:@"left_arrow.png"] forState:UIControlStateNormal]; + prevButton.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin; + [prevButton addTarget:self action:@selector(_moveCalendarToPreviousMonth) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:prevButton]; + self.prevButton = prevButton; + + UIButton *nextButton = [UIButton buttonWithType:UIButtonTypeCustom]; + [nextButton setImage:[UIImage imageNamed:@"right_arrow.png"] forState:UIControlStateNormal]; + nextButton.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleLeftMargin; + [nextButton addTarget:self action:@selector(_moveCalendarToNextMonth) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:nextButton]; + self.nextButton = nextButton; + } +} + +- (void)setupDayOfWeekLabels +{ + if (!self.suppressDayLabels) { + UIView *daysHeader = [[UIView alloc] initWithFrame:CGRectZero]; + daysHeader.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleWidth; + [self.calendarContainer addSubview:daysHeader]; + self.daysHeader = daysHeader; + + NSMutableArray *labels = [NSMutableArray array]; + for (int i = 0; i < 7; ++i) { + UILabel *dayOfWeekLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + dayOfWeekLabel.textAlignment = NSTextAlignmentCenter; + dayOfWeekLabel.backgroundColor = [UIColor clearColor]; + dayOfWeekLabel.shadowColor = [UIColor whiteColor]; + dayOfWeekLabel.shadowOffset = CGSizeMake(0, 1); + [labels addObject:dayOfWeekLabel]; + [self.calendarContainer addSubview:dayOfWeekLabel]; + } + self.dayOfWeekLabels = labels; + [self _updateDayOfWeekLabels]; } - return self; } -- (id)initWithFrame:(CGRect)frame { - return [self initWithStartDay:startSunday frame:frame]; +- (NSInteger)calendarMarginForStyle:(CKCalendarStyle)style +{ + return style == CKCalendarStyleFlat ? CALENDAR_MARGIN_FLAT : CALENDAR_MARGIN_SKEW; } - (id)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) { - [self _init:startSunday]; + [self _init:startSunday style:CKCalendarStyleSkeuomorphic]; } return self; } @@ -245,34 +326,21 @@ - (id)initWithCoder:(NSCoder *)aDecoder { - (void)layoutSubviews { [super layoutSubviews]; - CGFloat containerWidth = self.bounds.size.width - (CALENDAR_MARGIN * 2); - self.cellWidth = (floorf(containerWidth / 7.0)) - CELL_BORDER_WIDTH; - - NSInteger numberOfWeeksToShow = 6; - if (self.adaptHeightToNumberOfWeeksInMonth) { - numberOfWeeksToShow = [self _numberOfWeeksInMonthContainingDate:self.monthShowing]; - } - CGFloat containerHeight = (numberOfWeeksToShow * (self.cellWidth + CELL_BORDER_WIDTH) + DAYS_HEADER_HEIGHT); + CGFloat containerWidth = [self containerWidthForStyle:self.style]; + self.cellWidth = [self cellWidthForStyle:self.style]; CGRect newFrame = self.frame; - newFrame.size.height = containerHeight + CALENDAR_MARGIN + TOP_HEIGHT; + newFrame.size.height = [self computeFullFrameHeight]; self.frame = newFrame; self.highlight.frame = CGRectMake(1, 1, self.bounds.size.width - 2, 1); - self.titleLabel.text = [self.dateFormatter stringFromDate:_monthShowing]; - self.titleLabel.frame = CGRectMake(0, 0, self.bounds.size.width, TOP_HEIGHT); - self.prevButton.frame = CGRectMake(BUTTON_MARGIN, BUTTON_MARGIN, 48, 38); - self.nextButton.frame = CGRectMake(self.bounds.size.width - 48 - BUTTON_MARGIN, BUTTON_MARGIN, 48, 38); + [self layoutTitleHeader]; - self.calendarContainer.frame = CGRectMake(CALENDAR_MARGIN, CGRectGetMaxY(self.titleLabel.frame), containerWidth, containerHeight); + self.calendarContainer.frame = CGRectMake(self.calendarMargin, CGRectGetMaxY(self.titleLabel.frame), containerWidth, [self computeContainerHeight]); self.daysHeader.frame = CGRectMake(0, 0, self.calendarContainer.frame.size.width, DAYS_HEADER_HEIGHT); - CGRect lastDayFrame = CGRectZero; - for (UILabel *dayLabel in self.dayOfWeekLabels) { - dayLabel.frame = CGRectMake(CGRectGetMaxX(lastDayFrame) + CELL_BORDER_WIDTH, lastDayFrame.origin.y, self.cellWidth, self.daysHeader.frame.size.height); - lastDayFrame = dayLabel.frame; - } + [self loadDaysLabelsIntoDaysHeaderView]; for (DateButton *dateButton in self.dateButtons) { dateButton.date = nil; @@ -289,7 +357,7 @@ - (void)layoutSubviews { NSDate *endDate = [self _firstDayOfNextMonthContainingDate:self.monthShowing]; if (!self.onlyShowCurrentMonth) { NSDateComponents *comps = [[NSDateComponents alloc] init]; - [comps setWeek:numberOfWeeksToShow]; + [comps setWeek:[self numberOfWeeksToShow]]; endDate = [self.calendar dateByAddingComponents:comps toDate:date options:0]; } @@ -302,8 +370,9 @@ - (void)layoutSubviews { if ([self _dateIsToday:dateButton.date]) { item.textColor = UIColorFromRGB(0xF2F2F2); item.backgroundColor = [UIColor lightGrayColor]; - } else if (!self.onlyShowCurrentMonth && [self _compareByMonth:date toDate:self.monthShowing] != NSOrderedSame) { + } else if ([self _dayIsOutsideOfCurrentMonth:date]) { item.textColor = [UIColor lightGrayColor]; + item.backgroundColor = self.outOfMonthBackgroundColor; } if (self.delegate && [self.delegate respondsToSelector:@selector(calendar:configureDateItem:forDate:)]) { @@ -331,6 +400,114 @@ - (void)layoutSubviews { } } +- (int)computeContainerHeight +{ + int headerHeight = self.suppressDayLabels ? 0 : DAYS_HEADER_HEIGHT; + return ([self numberOfWeeksToShow] * (self.cellWidth + CELL_BORDER_WIDTH) + headerHeight); +} + +- (int)computeFullFrameHeight +{ + int topHeight = self.suppressHeader ? 0 : TOP_HEIGHT; + return [self computeContainerHeight] + self.calendarMargin + topHeight; +} + +- (int)numberOfWeeksToShow +{ + NSInteger numberOfWeeksToShow = 6; + if (self.adaptHeightToNumberOfWeeksInMonth) { + numberOfWeeksToShow = [self _numberOfWeeksInMonthContainingDate:self.monthShowing]; + } + + return numberOfWeeksToShow; +} + +- (void)layoutTitleHeader { + if (!self.suppressHeader) { + self.titleLabel.text = [self.dateFormatter stringFromDate:_monthShowing]; + self.titleLabel.frame = CGRectMake(0, 0, self.bounds.size.width, TOP_HEIGHT); + self.prevButton.frame = CGRectMake(BUTTON_MARGIN, BUTTON_MARGIN, 48, 38); + self.nextButton.frame = CGRectMake(self.bounds.size.width - 48 - BUTTON_MARGIN, BUTTON_MARGIN, 48, 38); + } +} + + +- (BOOL)_dayIsOutsideOfCurrentMonth:(NSDate *)date +{ + return !self.onlyShowCurrentMonth && [self _compareByMonth:date toDate:self.monthShowing] != NSOrderedSame; +} + + +- (void)loadDaysLabelsIntoDaysHeaderView +{ + if (!self.suppressDayLabels) { + CGRect lastDayFrame = CGRectZero; + for (UILabel *dayLabel in self.dayOfWeekLabels) { + dayLabel.frame = CGRectMake(CGRectGetMaxX(lastDayFrame) + CELL_BORDER_WIDTH, lastDayFrame.origin.y, self.cellWidth, self.daysHeader.frame.size.height); + lastDayFrame = dayLabel.frame; + [self.calendarContainer bringSubviewToFront:dayLabel]; + } + } +} + +- (CGFloat)cornerRadiusForStyle:(CKCalendarStyle)style +{ + CGFloat cornerRadius = 0; + + switch (style) { + case CKCalendarStyleSkeuomorphic: + cornerRadius = 6.0f; + break; + case CKCalendarStyleFlat: + cornerRadius = 0.0f; + break; + default: + break; + } + + return cornerRadius; +} + +- (CGFloat)containerWidthForStyle:(CKCalendarStyle)style +{ + CGFloat containerWidth = 0; + + switch (style) { + case CKCalendarStyleSkeuomorphic: + containerWidth = self.bounds.size.width - (self.calendarMargin * 2); + break; + case CKCalendarStyleFlat: + containerWidth = self.bounds.size.width; + break; + default: + containerWidth = self.bounds.size.width - (self.calendarMargin * 2); + break; + } + + return containerWidth; +} + +- (CGFloat)cellWidthForStyle:(CKCalendarStyle)style +{ + CGFloat containerWidth = [self containerWidthForStyle:style]; + + CGFloat cellWidth = 0; + + switch (style) { + case CKCalendarStyleSkeuomorphic: + cellWidth = (floorf(containerWidth / 7.0)) - CELL_BORDER_WIDTH; + break; + case CKCalendarStyleFlat: + cellWidth = (containerWidth / 7.0) - CELL_BORDER_WIDTH; + break; + default: + cellWidth = (floorf(containerWidth / 7.0)) - CELL_BORDER_WIDTH; + break; + } + + return cellWidth; +} + - (void)_updateDayOfWeekLabels { NSArray *weekdays = [self.dateFormatter shortWeekdaySymbols]; // adjust array depending on which weekday should be first @@ -415,7 +592,7 @@ - (void)reloadDates:(NSArray *)dates { [self setNeedsLayout]; } -- (void)_setDefaultStyle { +- (void)_setDefaultStyle:(CKCalendarStyle)style { self.backgroundColor = UIColorFromRGB(0x393B40); [self setTitleColor:[UIColor whiteColor]]; @@ -423,7 +600,10 @@ - (void)_setDefaultStyle { [self setDayOfWeekFont:[UIFont boldSystemFontOfSize:12.0]]; [self setDayOfWeekTextColor:UIColorFromRGB(0x999999)]; - [self setDayOfWeekBottomColor:UIColorFromRGB(0xCCCFD5) topColor:[UIColor whiteColor]]; + + if (style == CKCalendarStyleSkeuomorphic) { + [self setDayOfWeekBottomColor:UIColorFromRGB(0xCCCFD5) topColor:[UIColor whiteColor]]; + } [self setDateFont:[UIFont boldSystemFontOfSize:16.0f]]; [self setDateBorderColor:UIColorFromRGB(0xDAE1E6)]; @@ -528,7 +708,19 @@ - (UIColor *)dayOfWeekTextColor { } - (void)setDayOfWeekBottomColor:(UIColor *)bottomColor topColor:(UIColor *)topColor { - [self.daysHeader setColors:[NSArray arrayWithObjects:topColor, bottomColor, nil]]; + [self.daysHeader removeFromSuperview]; + self.daysHeader = nil; + + GradientView *gradientView = [[GradientView alloc] initWithFrame:CGRectZero]; + gradientView.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleWidth; + + [gradientView setColors:[NSArray arrayWithObjects:topColor, bottomColor, nil]]; + self.daysHeader = gradientView; + + [self.calendarContainer addSubview:self.daysHeader]; + self.daysHeader.frame = CGRectMake(0, 0, self.calendarContainer.frame.size.width, DAYS_HEADER_HEIGHT); + + [self loadDaysLabelsIntoDaysHeaderView]; } - (void)setDateFont:(UIFont *)font {