DKWeeklyCalendarView.m 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. //
  2. // DKWeeklyCalendarView.m
  3. // Deputy
  4. //
  5. // Created by Caesar on 30/10/2014.
  6. // Copyright (c) 2014 Caesar Li. All rights reserved.
  7. //
  8. #import "DKWeeklyCalendarView.h"
  9. #import "DailyCalendarView.h"
  10. #import "DayTitleLabel.h"
  11. #import "BRDatePickerView.h"
  12. #import "NSDate+CL.h"
  13. #import "UIColor+CL.h"
  14. #import "NSDictionary+CL.h"
  15. #import "UIImage+CL.h"
  16. #define WEEKLY_VIEW_COUNT 7
  17. #define DAY_TITLE_VIEW_HEIGHT 20.f// 原来20
  18. #define DAY_TITLE_FONT_SIZE 11.f
  19. #define DATE_TITLE_MARGIN_TOP 0.f
  20. #define DATE_VIEW_MARGIN 3.f
  21. #define DATE_VIEW_HEIGHT 28.f
  22. #define DATE_LABEL_MARGIN_LEFT 9.f
  23. #define DATE_LABEL_INFO_WIDTH 160.f
  24. #define DATE_LABEL_INFO_HEIGHT 40.f
  25. #define WEATHER_ICON_WIDTH 20
  26. #define WEATHER_ICON_HEIGHT 20
  27. #define WEATHER_ICON_LEFT 90
  28. #define WEATHER_ICON_MARGIN_TOP 9
  29. //Attribute Keys
  30. NSString *const CLCalendarWeekStartDay = @"CLCalendarWeekStartDay";
  31. NSString *const CLCalendarDayTitleTextColor = @"CLCalendarDayTitleTextColor";
  32. NSString *const CLCalendarSelectedDatePrintFormat = @"CLCalendarSelectedDatePrintFormat";
  33. NSString *const CLCalendarSelectedDatePrintColor = @"CLCalendarSelectedDatePrintColor";
  34. NSString *const CLCalendarSelectedDatePrintFontSize = @"CLCalendarSelectedDatePrintFontSize";
  35. NSString *const CLCalendarBackgroundImageColor = @"CLCalendarBackgroundImageColor";
  36. //Default Values
  37. static NSInteger const CLCalendarWeekStartDayDefault = 1;
  38. static NSInteger const CLCalendarDayTitleTextColorDefault = 0xff0000;
  39. static NSString* const CLCalendarSelectedDatePrintFormatDefault = @"yyyy.MM";
  40. static float const CLCalendarSelectedDatePrintFontSizeDefault = 13.f;
  41. @interface DKWeeklyCalendarView()<DailyCalendarViewDelegate, UIGestureRecognizerDelegate>
  42. @property (nonatomic, strong) UIView *dailySubViewContainer;
  43. @property (nonatomic, strong) UIView *dayTitleSubViewContainer;
  44. @property (nonatomic, strong) UIImageView *backgroundImageView;
  45. @property (nonatomic, strong) UIView *dailyInfoSubViewContainer;
  46. @property (nonatomic, strong) UIImageView *weatherIcon;
  47. @property (nonatomic, strong) UILabel *dateInfoLabel;
  48. @property (nonatomic, strong) NSDate *startDate;
  49. @property (nonatomic, strong) NSDate *endDate;
  50. @property (nonatomic, strong) NSDictionary *arrDailyWeather;
  51. @property (nonatomic, strong) NSNumber *weekStartConfig;
  52. @property (nonatomic, strong) UIColor *dayTitleTextColor;
  53. @property (nonatomic, strong) NSString *selectedDatePrintFormat;
  54. @property (nonatomic, strong) UIColor *selectedDatePrintColor;
  55. @property (nonatomic) float selectedDatePrintFontSize;
  56. @property (nonatomic, strong) UIColor *backgroundImageColor;
  57. @property (nonatomic, strong) NSString *currentSelectDate;
  58. @end
  59. @implementation DKWeeklyCalendarView
  60. - (id)initWithFrame:(CGRect)frame
  61. {
  62. self = [super initWithFrame:frame];
  63. if (self) {
  64. // Initialization code
  65. [self addSubview:self.backgroundImageView];
  66. self.arrDailyWeather = @{};
  67. }
  68. return self;
  69. }
  70. -(void)setDelegate:(id<DKWeeklyCalendarViewDelegate>)delegate
  71. {
  72. _delegate = delegate;
  73. [self applyCustomDefaults];
  74. }
  75. -(void)applyCustomDefaults
  76. {
  77. NSDictionary *attributes;
  78. if ([self.delegate respondsToSelector:@selector(CLCalendarBehaviorAttributes)]) {
  79. attributes = [self.delegate CLCalendarBehaviorAttributes];
  80. }
  81. self.weekStartConfig = attributes[CLCalendarWeekStartDay] ? attributes[CLCalendarWeekStartDay] : [NSNumber numberWithInt:CLCalendarWeekStartDayDefault];
  82. self.dayTitleTextColor = attributes[CLCalendarDayTitleTextColor]? attributes[CLCalendarDayTitleTextColor]:[UIColor colorWithHex:CLCalendarDayTitleTextColorDefault];
  83. self.selectedDatePrintFormat = attributes[CLCalendarSelectedDatePrintFormat]? attributes[CLCalendarSelectedDatePrintFormat] : CLCalendarSelectedDatePrintFormatDefault;
  84. self.selectedDatePrintColor = attributes[CLCalendarSelectedDatePrintColor]? attributes[CLCalendarSelectedDatePrintColor] : [UIColor blackColor];
  85. self.selectedDatePrintFontSize = attributes[CLCalendarSelectedDatePrintFontSize]? [attributes[CLCalendarSelectedDatePrintFontSize] floatValue] : CLCalendarSelectedDatePrintFontSizeDefault;
  86. NSLog(@"%@ %f", attributes[CLCalendarBackgroundImageColor], self.selectedDatePrintFontSize);
  87. self.backgroundImageColor = attributes[CLCalendarBackgroundImageColor];
  88. [self setNeedsDisplay];
  89. }
  90. /**
  91. 日期信息控件布局
  92. @return <#return value description#>
  93. */
  94. -(UIView *)dailyInfoSubViewContainer
  95. {
  96. if(!_dailyInfoSubViewContainer){
  97. //_dailyInfoSubViewContainer = [[UIView alloc] initWithFrame:CGRectMake(0, DATE_TITLE_MARGIN_TOP+DAY_TITLE_VIEW_HEIGHT + DATE_VIEW_HEIGHT + DATE_VIEW_MARGIN * 2, self.bounds.size.width, DATE_LABEL_INFO_HEIGHT)];
  98. _dailyInfoSubViewContainer = [[UIView alloc] initWithFrame:CGRectMake(0, DATE_TITLE_MARGIN_TOP, self.bounds.size.width, DATE_LABEL_INFO_HEIGHT)];
  99. _dailyInfoSubViewContainer.userInteractionEnabled = YES;
  100. //_dailyInfoSubViewContainer.backgroundColor = [UIColor greenColor];
  101. [_dailyInfoSubViewContainer addSubview:self.weatherIcon];
  102. [_dailyInfoSubViewContainer addSubview:self.dateInfoLabel];
  103. UITapGestureRecognizer *singleFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dailyInfoViewDidClick:)];
  104. [_dailyInfoSubViewContainer addGestureRecognizer:singleFingerTap];
  105. }
  106. return _dailyInfoSubViewContainer;
  107. }
  108. -(UIImageView *)weatherIcon
  109. {
  110. if(!_weatherIcon){
  111. _weatherIcon = [[UIImageView alloc] initWithFrame:CGRectMake(WEATHER_ICON_LEFT, WEATHER_ICON_MARGIN_TOP, WEATHER_ICON_WIDTH, WEATHER_ICON_HEIGHT)];
  112. }
  113. return _weatherIcon;
  114. }
  115. -(UILabel *)dateInfoLabel
  116. {
  117. if(!_dateInfoLabel){
  118. _dateInfoLabel = [[UILabel alloc] initWithFrame:CGRectMake(WEATHER_ICON_LEFT+WEATHER_ICON_WIDTH+DATE_LABEL_MARGIN_LEFT, 0, DATE_LABEL_INFO_WIDTH, DATE_LABEL_INFO_HEIGHT)];
  119. _dateInfoLabel.textAlignment = NSTextAlignmentCenter;
  120. _dateInfoLabel.userInteractionEnabled = YES;
  121. }
  122. _dateInfoLabel.font = [UIFont systemFontOfSize: self.selectedDatePrintFontSize];
  123. _dateInfoLabel.textColor = self.selectedDatePrintColor;
  124. _dateInfoLabel.backgroundColor = [UIColor clearColor];
  125. return _dateInfoLabel;
  126. }
  127. -(UIView *)dayTitleSubViewContainer
  128. {
  129. if(!_dayTitleSubViewContainer){
  130. _dayTitleSubViewContainer = [[UIImageView alloc] initWithFrame:CGRectMake(0, DAY_TITLE_VIEW_HEIGHT, self.bounds.size.width, DAY_TITLE_VIEW_HEIGHT)];
  131. _dayTitleSubViewContainer.backgroundColor = [UIColor clearColor];
  132. _dayTitleSubViewContainer.userInteractionEnabled = YES;
  133. }
  134. return _dayTitleSubViewContainer;
  135. }
  136. -(UIView *)dailySubViewContainer
  137. {
  138. if(!_dailySubViewContainer){
  139. _dailySubViewContainer = [[UIImageView alloc] initWithFrame:CGRectMake(0, DATE_TITLE_MARGIN_TOP+DATE_LABEL_INFO_HEIGHT+DATE_VIEW_MARGIN, self.bounds.size.width, DATE_VIEW_HEIGHT)];
  140. _dailySubViewContainer.backgroundColor = [UIColor clearColor];
  141. _dailySubViewContainer.userInteractionEnabled = YES;
  142. }
  143. return _dailySubViewContainer;
  144. }
  145. -(UIImageView *)backgroundImageView
  146. {
  147. if(!_backgroundImageView){
  148. _backgroundImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height)];
  149. _backgroundImageView.userInteractionEnabled = YES;
  150. //[_backgroundImageView addSubview:self.dayTitleSubViewContainer];
  151. [_backgroundImageView addSubview:self.dailySubViewContainer];
  152. [_backgroundImageView addSubview:self.dailyInfoSubViewContainer];
  153. //Apply swipe gesture
  154. UISwipeGestureRecognizer *recognizerRight;
  155. recognizerRight.delegate=self;
  156. recognizerRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeRight:)];
  157. [recognizerRight setDirection:UISwipeGestureRecognizerDirectionRight];
  158. [_backgroundImageView addGestureRecognizer:recognizerRight];
  159. UISwipeGestureRecognizer *recognizerLeft;
  160. recognizerLeft.delegate=self;
  161. recognizerLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeLeft:)];
  162. [recognizerLeft setDirection:UISwipeGestureRecognizerDirectionLeft];
  163. [_backgroundImageView addGestureRecognizer:recognizerLeft];
  164. }
  165. _backgroundImageView.backgroundColor = self.backgroundImageColor? self.backgroundImageColor : [UIColor colorWithPatternImage:[UIImage calendarBackgroundImage:self.bounds.size.height]];;
  166. return _backgroundImageView;
  167. }
  168. -(void)initDailyViews
  169. {
  170. CGFloat dailyWidth = self.bounds.size.width/WEEKLY_VIEW_COUNT;
  171. NSDate *today = [NSDate new];
  172. NSDate *dtWeekStart = [today getWeekStartDate:self.weekStartConfig.integerValue];
  173. self.startDate = dtWeekStart;
  174. for (UIView *v in [self.dailySubViewContainer subviews]){
  175. [v removeFromSuperview];
  176. }
  177. for (UIView *v in [self.dayTitleSubViewContainer subviews]){
  178. [v removeFromSuperview];
  179. }
  180. for(int i = 0; i < WEEKLY_VIEW_COUNT; i++){
  181. NSDate *dt = [dtWeekStart addDays:i];
  182. [self dayTitleViewForDate: dt inFrame: CGRectMake(dailyWidth*i, 0, dailyWidth, DAY_TITLE_VIEW_HEIGHT)];
  183. [self dailyViewForDate:dt inFrame: CGRectMake(dailyWidth*i, 0, dailyWidth, DATE_VIEW_HEIGHT) ];
  184. self.endDate = dt;
  185. }
  186. [self dailyCalendarViewDidSelect:[NSDate new]];
  187. }
  188. -(UILabel *)dayTitleViewForDate: (NSDate *)date inFrame: (CGRect)frame
  189. {
  190. DayTitleLabel *dayTitleLabel = [[DayTitleLabel alloc] initWithFrame:frame];
  191. dayTitleLabel.backgroundColor = [UIColor clearColor];
  192. dayTitleLabel.textColor = self.dayTitleTextColor;
  193. dayTitleLabel.textAlignment = NSTextAlignmentCenter;
  194. dayTitleLabel.font = [UIFont systemFontOfSize:DAY_TITLE_FONT_SIZE];
  195. dayTitleLabel.text = [[date getDayOfWeekShortString] uppercaseString];
  196. dayTitleLabel.date = date;
  197. dayTitleLabel.userInteractionEnabled = YES;
  198. UITapGestureRecognizer *singleFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dayTitleViewDidClick:)];
  199. [dayTitleLabel addGestureRecognizer:singleFingerTap];
  200. [self.dayTitleSubViewContainer addSubview:dayTitleLabel];
  201. return dayTitleLabel;
  202. }
  203. -(DailyCalendarView *)dailyViewForDate: (NSDate *)date inFrame: (CGRect)frame
  204. {
  205. DailyCalendarView *view = [[DailyCalendarView alloc] initWithFrame:frame];
  206. view.date = date;
  207. view.backgroundColor = [UIColor clearColor];
  208. view.delegate = self;
  209. [self.dailySubViewContainer addSubview:view];
  210. return view;
  211. }
  212. // Only override drawRect: if you perform custom drawing.
  213. // An empty implementation adversely affects performance during animation.
  214. - (void)drawRect:(CGRect)rect
  215. {
  216. // Drawing code
  217. [self initDailyViews];
  218. }
  219. -(void)markDateSelected:(NSDate *)date
  220. {
  221. for (DailyCalendarView *v in [self.dailySubViewContainer subviews]){
  222. [v markSelected:([v.date isSameDateWith:date])];
  223. }
  224. self.selectedDate = date;
  225. NSDateFormatter *dayFormatter = [[NSDateFormatter alloc] init];
  226. [dayFormatter setDateFormat:self.selectedDatePrintFormat];
  227. NSString *strDate = [dayFormatter stringFromDate:date];
  228. if([date isDateToday]){
  229. strDate = [NSString stringWithFormat:@"%@", strDate ];
  230. }
  231. [self adjustDailyInfoLabelAndWeatherIcon : NO];
  232. self.dateInfoLabel.text = strDate;
  233. }
  234. -(void)dailyInfoViewDidClick: (UIGestureRecognizer *)tap
  235. {
  236. //Click to jump back to today
  237. BRDatePickerView *_dealdatePicker = [BRDatePickerView PickerAlertWithTitle:@""];
  238. [_dealdatePicker configureSelectionBlock:^(NSString *date){
  239. self.currentSelectDate = date;
  240. }
  241. andCompletionBlock:^(void){
  242. NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
  243. [formatter setDateFormat:@"yyyy-MM-dd"];
  244. NSDate *resDate = [formatter dateFromString:self.currentSelectDate];
  245. [self redrawToDate:resDate];
  246. }
  247. andCancelBlock:^(void){
  248. }];
  249. [_dealdatePicker show];
  250. }
  251. -(void)dayTitleViewDidClick: (UIGestureRecognizer *)tap
  252. {
  253. [self redrawToDate:((DayTitleLabel *)tap.view).date];
  254. }
  255. -(void)redrawToDate:(NSDate *)dt
  256. {
  257. if(![dt isWithinDate:self.startDate toDate:self.endDate]){
  258. BOOL swipeRight = ([dt compare:self.startDate] == NSOrderedAscending);
  259. [self delegateSwipeAnimation:swipeRight blnToday:[dt isDateToday] selectedDate:dt];
  260. }
  261. [self dailyCalendarViewDidSelect:dt];
  262. }
  263. -(void)redrawCalenderData
  264. {
  265. [self redrawToDate:self.selectedDate];
  266. }
  267. -(void)adjustDailyInfoLabelAndWeatherIcon: (BOOL)blnShowWeatherIcon
  268. {
  269. self.dateInfoLabel.textAlignment = (blnShowWeatherIcon)?NSTextAlignmentLeft:NSTextAlignmentCenter;
  270. if(blnShowWeatherIcon){
  271. if([self.selectedDate isDateToday]){
  272. self.weatherIcon.frame = CGRectMake(WEATHER_ICON_LEFT-20, WEATHER_ICON_MARGIN_TOP, WEATHER_ICON_WIDTH, WEATHER_ICON_HEIGHT);
  273. self.dateInfoLabel.frame = CGRectMake(WEATHER_ICON_LEFT+WEATHER_ICON_WIDTH+DATE_LABEL_MARGIN_LEFT-20, 0, DATE_LABEL_INFO_WIDTH, DATE_LABEL_INFO_HEIGHT);
  274. }else{
  275. self.weatherIcon.frame = CGRectMake(WEATHER_ICON_LEFT, WEATHER_ICON_MARGIN_TOP, WEATHER_ICON_WIDTH, WEATHER_ICON_HEIGHT);
  276. self.dateInfoLabel.frame = CGRectMake(WEATHER_ICON_LEFT+WEATHER_ICON_WIDTH+DATE_LABEL_MARGIN_LEFT, 0, DATE_LABEL_INFO_WIDTH, DATE_LABEL_INFO_HEIGHT);
  277. }
  278. }else{
  279. self.dateInfoLabel.frame = CGRectMake( (self.bounds.size.width - DATE_LABEL_INFO_WIDTH)/2, 0, DATE_LABEL_INFO_WIDTH, DATE_LABEL_INFO_HEIGHT);
  280. }
  281. self.weatherIcon.hidden = !blnShowWeatherIcon;
  282. }
  283. #pragma swipe
  284. -(void)swipeLeft: (UISwipeGestureRecognizer *)swipe
  285. {
  286. [self delegateSwipeAnimation: NO blnToday:NO selectedDate:nil];
  287. }
  288. -(void)swipeRight: (UISwipeGestureRecognizer *)swipe
  289. {
  290. [self delegateSwipeAnimation: YES blnToday:NO selectedDate:nil];
  291. }
  292. -(void)delegateSwipeAnimation: (BOOL)blnSwipeRight blnToday: (BOOL)blnToday selectedDate:(NSDate *)selectedDate
  293. {
  294. CATransition *animation = [CATransition animation];
  295. [animation setDelegate:self];
  296. [animation setType:kCATransitionPush];
  297. [animation setSubtype:(blnSwipeRight)?kCATransitionFromLeft:kCATransitionFromRight];
  298. [animation setDuration:0.50];
  299. [animation setTimingFunction:
  300. [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
  301. [self.dailySubViewContainer.layer addAnimation:animation forKey:kCATransition];
  302. NSMutableDictionary *data = @{@"blnSwipeRight": [NSNumber numberWithBool:blnSwipeRight], @"blnToday":[NSNumber numberWithBool:blnToday]}.mutableCopy;
  303. if(selectedDate){
  304. [data setObject:selectedDate forKey:@"selectedDate"];
  305. }
  306. [self performSelector:@selector(renderSwipeDates:) withObject:data afterDelay:0.05f];
  307. }
  308. -(void)renderSwipeDates: (NSDictionary*)param
  309. {
  310. int step = ([[param objectForKey:@"blnSwipeRight"] boolValue])? -1 : 1;
  311. BOOL blnToday = [[param objectForKey:@"blnToday"] boolValue];
  312. NSDate *selectedDate = [param objectForKeyWithNil:@"selectedDate"];
  313. CGFloat dailyWidth = self.bounds.size.width/WEEKLY_VIEW_COUNT;
  314. NSDate *dtStart;
  315. if(blnToday){
  316. dtStart = [[NSDate new] getWeekStartDate:self.weekStartConfig.integerValue];
  317. }else{
  318. dtStart = (selectedDate)? [selectedDate getWeekStartDate:self.weekStartConfig.integerValue]:[self.startDate addDays:step*7];
  319. }
  320. self.startDate = dtStart;
  321. for (UIView *v in [self.dailySubViewContainer subviews]){
  322. [v removeFromSuperview];
  323. }
  324. for(int i = 0; i < WEEKLY_VIEW_COUNT; i++){
  325. NSDate *dt = [dtStart addDays:i];
  326. DailyCalendarView* view = [self dailyViewForDate:dt inFrame: CGRectMake(dailyWidth*i, 0, dailyWidth, DATE_VIEW_HEIGHT) ];
  327. DayTitleLabel *titleLabel = [[self.dayTitleSubViewContainer subviews] objectAtIndex:i];
  328. titleLabel.date = dt;
  329. [view markSelected:([view.date isSameDateWith:self.selectedDate])];
  330. self.endDate = dt;
  331. }
  332. }
  333. -(void)updateWeatherIconByKey:(NSString *)key
  334. {
  335. if(!key){
  336. [self adjustDailyInfoLabelAndWeatherIcon:NO];
  337. return;
  338. }
  339. self.weatherIcon.image = [UIImage imageNamed:key];
  340. [self adjustDailyInfoLabelAndWeatherIcon:YES];
  341. }
  342. #pragma DeputyDailyCalendarViewDelegate
  343. -(void)dailyCalendarViewDidSelect:(NSDate *)date
  344. {
  345. [self markDateSelected:date];
  346. [self.delegate dailyCalendarViewDidSelect:date];
  347. }
  348. @end