FSCalendar/Pod/Classes/FSCalendarUnit.m

340 lines
11 KiB
Objective-C

//
// FSCalendarViewUnit.m
// Pods
//
// Created by Wenchao Ding on 29/1/15.
//
//
#import "FSCalendarUnit.h"
#import "FSCalendarPage.h"
#import "NSDate+FSExtension.h"
#import "UIView+FSExtension.h"
#define kAnimationDuration 0.12
#define kPink [UIColor colorWithRed:198/255.0 green:51/255.0 blue:42/255.0 alpha:1.0]
#define kBlue [UIColor colorWithRed:31/255.0 green:119/255.0 blue:219/255.0 alpha:1.0]
@interface FSCalendarUnit ()
@property (strong, nonatomic) UILabel *titleLabel;
@property (readonly, nonatomic) FSCalendarUnitState absoluteState;
@property (readonly, nonatomic) CGFloat diameter;
@property (strong, nonatomic) NSMutableDictionary *unitColors;
@property (strong, nonatomic) NSMutableDictionary *titleColors;
@property (strong, nonatomic) NSMutableDictionary *subtitleColors;
@property (strong, nonatomic) CAShapeLayer *animLayer;
@property (strong, nonatomic) CAShapeLayer *eventLayer;
- (void)handleTap:(FSCalendarUnit *)unit;
@end
@implementation FSCalendarUnit
@synthesize titleFont = _titleFont, diameter = _diameter;
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
_titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
_titleLabel.textAlignment = NSTextAlignmentCenter;
_titleLabel.numberOfLines = 1;
_titleLabel.font = [UIFont systemFontOfSize:16];
[self addSubview:_titleLabel];
_titleFont = _titleLabel.font;
_subtitleFont = [_titleFont fontWithSize:11];
_unitColors = [NSMutableDictionary dictionaryWithCapacity:4];
_unitColors[@(FSCalendarUnitStateNormal)] = [UIColor clearColor];
_unitColors[@(FSCalendarUnitStateSelected)] = kBlue;
_unitColors[@(FSCalendarUnitStateDisabled)] = [UIColor clearColor];
_unitColors[@(FSCalendarUnitStatePlaceholder)] = [UIColor clearColor];
_unitColors[@(FSCalendarUnitStateToday)] = kPink;
_titleColors = [NSMutableDictionary dictionaryWithCapacity:4];
_titleColors[@(FSCalendarUnitStateNormal)] = [UIColor darkTextColor];
_titleColors[@(FSCalendarUnitStateWeekend)] = [UIColor darkTextColor];
_titleColors[@(FSCalendarUnitStateSelected)] = [UIColor whiteColor];
_titleColors[@(FSCalendarUnitStateDisabled)] = [UIColor grayColor];
_titleColors[@(FSCalendarUnitStatePlaceholder)] = [UIColor lightGrayColor];
_titleColors[@(FSCalendarUnitStateToday)] = [UIColor whiteColor];
_subtitleColors = [NSMutableDictionary dictionaryWithCapacity:4];
_subtitleColors[@(FSCalendarUnitStateNormal)] = [UIColor darkGrayColor];
_subtitleColors[@(FSCalendarUnitStateWeekend)] = [UIColor darkGrayColor];
_subtitleColors[@(FSCalendarUnitStateSelected)] = [UIColor whiteColor];
_subtitleColors[@(FSCalendarUnitStateDisabled)] = [UIColor lightGrayColor];
_subtitleColors[@(FSCalendarUnitStatePlaceholder)] = [UIColor lightGrayColor];
_subtitleColors[@(FSCalendarUnitStateToday)] = [UIColor whiteColor];
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
tapGesture.numberOfTapsRequired = 1;
tapGesture.numberOfTouchesRequired = 1;
tapGesture.cancelsTouchesInView = NO;
tapGesture.delaysTouchesBegan = NO;
[self addGestureRecognizer:tapGesture];
_animation = FSCalendarUnitAnimationScale;
_eventLayer = [CAShapeLayer layer];
_eventLayer.backgroundColor = [UIColor clearColor].CGColor;
_eventLayer.fillColor = [UIColor cyanColor].CGColor;
_eventLayer.path = [UIBezierPath bezierPathWithOvalInRect:_eventLayer.bounds].CGPath;
[self.layer addSublayer:_eventLayer];
_animLayer = [CAShapeLayer layer];
[self.layer insertSublayer:_animLayer below:_titleLabel.layer];
_style = FSCalendarUnitStyleCircle;
self.clipsToBounds = NO;
}
return self;
}
- (void)layoutSubviews
{
[super layoutSubviews];
_titleLabel.frame = self.bounds;
_titleLabel.fs_left = (self.fs_width - _titleLabel.fs_width)/2.0;
CGFloat diameter = self.diameter;
_animLayer.frame = CGRectMake((self.fs_width-diameter)/2, (_titleLabel.fs_height-diameter)/2, diameter, diameter);
switch (self.style) {
case FSCalendarUnitStyleCircle:
_animLayer.path = [UIBezierPath bezierPathWithOvalInRect:_animLayer.bounds].CGPath;
break;
case FSCalendarUnitStyleRectangle:
_animLayer.path = [UIBezierPath bezierPathWithRect:_animLayer.bounds].CGPath;
break;
default:
break;
}
_animLayer.fillColor = [self unitColorForState:self.absoluteState].CGColor;
if (_date) {
// set attribute title
_titleLabel.numberOfLines = 1;
NSMutableAttributedString *attributeString = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@", @(_date.fs_day)] attributes:
@{NSForegroundColorAttributeName:[self titleColorForState:self.absoluteState],NSFontAttributeName:_titleFont}];
NSString *subtitle = [_dataSource subtitleForUnit:self];
if (subtitle && ![subtitle isEqualToString:@""]) {
_titleLabel.numberOfLines = 2;
NSAttributedString *subtitleString = [[NSAttributedString alloc] initWithString:subtitle attributes:@{NSForegroundColorAttributeName:[self subtitleColorForState:self.absoluteState], NSFontAttributeName: _subtitleFont}];
[attributeString appendAttributedString:[[NSAttributedString alloc] initWithString:@"\n"]];
[attributeString appendAttributedString:subtitleString];
}
NSMutableParagraphStyle *paragraph = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
paragraph.lineSpacing = 0;
paragraph.alignment = NSTextAlignmentCenter;
paragraph.maximumLineHeight = _titleFont.lineHeight * 0.6;
[attributeString addAttribute:NSParagraphStyleAttributeName value:paragraph range:NSMakeRange(0, attributeString.length)];
_titleLabel.attributedText = attributeString;
_titleLabel.fs_top += _titleFont.lineHeight * 0.1;
}
_eventLayer.frame = CGRectMake((_animLayer.frame.size.width-5)/2+_animLayer.frame.origin.x, CGRectGetMaxY(_animLayer.frame), 5, 5);
_eventLayer.path = [UIBezierPath bezierPathWithOvalInRect:_eventLayer.bounds].CGPath;
_eventLayer.hidden = ![self.dataSource hasEventForUnit:self];
if ([self isSelected]) {
[self showAnimation];
}
}
#pragma mark - Public
- (void)setDate:(NSDate *)date
{
if (![_date isEqualToDate:date]) {
_date = [date copy];
}
[self setNeedsLayout];
}
- (void)setUnitColor:(UIColor *)backgroundColor forState:(FSCalendarUnitState)state
{
if ([[self unitColorForState:state] isEqual:backgroundColor]) {
return;
}
if (backgroundColor) {
_unitColors[@(state)] = backgroundColor;
} else {
[_unitColors removeObjectForKey:@(state)];
}
[self setNeedsLayout];
}
- (UIColor *)unitColorForState:(FSCalendarUnitState)state
{
return _unitColors[@(state)];
}
- (void)setTitleColor:(UIColor *)titleColor forState:(FSCalendarUnitState)state
{
if ([[self titleColorForState:state] isEqual:titleColor]) {
return;
}
if (titleColor) {
_titleColors[@(state)] = titleColor;
} else {
[_titleColors removeObjectForKey:@(state)];
}
[self setNeedsLayout];
}
- (UIColor *)titleColorForState:(FSCalendarUnitState)state
{
return _titleColors[@(state)];
}
- (void)setSubtitleColor:(UIColor *)subtitleColor forState:(FSCalendarUnitState)state
{
if ([[self subtitleColorForState:state] isEqual:subtitleColor]) {
return;
}
if (subtitleColor) {
_subtitleColors[@(state)] = subtitleColor;
} else {
[_subtitleColors removeObjectForKey:@(state)];
}
[self setNeedsLayout];
}
- (UIColor *)subtitleColorForState:(FSCalendarUnitState)state
{
return _subtitleColors[@(state)];
}
- (void)setTitleFont:(UIFont *)titleFont
{
if (_titleFont != titleFont) {
_titleFont = titleFont;
_diameter = [@"1\n1" boundingRectWithSize:self.frame.size options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:_titleFont} context:nil].size.height + 1;
[self setNeedsLayout];
}
}
- (void)setSubtitleFont:(UIFont *)subtitleFont
{
if (_subtitleFont != subtitleFont) {
_subtitleFont = subtitleFont;
[self setNeedsLayout];
}
}
- (void)setEventColor:(UIColor *)eventColor
{
_eventLayer.fillColor = eventColor.CGColor;
}
- (UIColor *)eventColor
{
return [UIColor colorWithCGColor:_eventLayer.fillColor];
}
- (void)setStyle:(FSCalendarUnitStyle)style
{
if (_style != style) {
_style = style;
[self setNeedsLayout];
}
}
#pragma mark - Target Action
- (void)handleTap:(id)sender
{
[self.delegate handleUnitTap:self];
}
#pragma mark - Private
- (CGFloat)diameter
{
if (!_diameter) {
_diameter = [@"1\n1" boundingRectWithSize:self.frame.size options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:_titleFont} context:nil].size.height;
}
return _diameter;
}
- (BOOL)isSelected
{
return [self.dataSource unitIsSelected:self];
}
- (BOOL)isPlaceholder
{
return [_dataSource unitIsPlaceholder:self];
}
- (BOOL)isToday
{
return [_dataSource unitIsToday:self];
}
- (BOOL)isWeekend
{
return self.date.fs_weekday == 1 || self.date.fs_weekday == 7;
}
- (void)showAnimation
{
if (_animation == FSCalendarUnitAnimationNone) {
return;
}
if (_animation == FSCalendarUnitAnimationScale) {
CAAnimationGroup *group = [CAAnimationGroup animation];
CABasicAnimation *zoomOut = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
zoomOut.fromValue = @0.3;
zoomOut.toValue = @1.2;
zoomOut.duration = kAnimationDuration/4*3;
CABasicAnimation *zoomIn = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
zoomIn.fromValue = @1.2;
zoomIn.toValue = @1.0;
zoomIn.beginTime = kAnimationDuration/4*3;
zoomIn.duration = kAnimationDuration/4;
group.duration = kAnimationDuration;
group.animations = @[zoomOut, zoomIn];
[_animLayer addAnimation:group forKey:@"bounce"];
} else if (_animation == FSCalendarUnitAnimationShade) {
[UIView transitionWithView:self duration:kAnimationDuration options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
[self setNeedsLayout];
} completion:nil];
}
}
- (FSCalendarUnitState)absoluteState
{
if (self.isSelected) {
return FSCalendarUnitStateSelected;
}
if (self.isToday) {
return FSCalendarUnitStateToday;
}
if (self.isPlaceholder) {
return FSCalendarUnitStatePlaceholder;
}
if (self.isWeekend) {
return FSCalendarUnitStateWeekend;
}
return FSCalendarUnitStateNormal;
}
@end