mirror of
https://github.com/danog/Telegram.git
synced 2024-12-03 09:57:46 +01:00
371 lines
13 KiB
Objective-C
371 lines
13 KiB
Objective-C
#import "TGCheckButtonView.h"
|
|
#import "TGColor.h"
|
|
|
|
@interface TGCheckButtonView ()
|
|
{
|
|
UIView *_wrapperView;
|
|
|
|
CALayer *_checkBackground;
|
|
|
|
TGCheckButtonStyle _style;
|
|
CGSize _size;
|
|
bool _borderOnTop;
|
|
UIImage *_fillImage;
|
|
|
|
UIView *_checkView;
|
|
UIImageView *_checkFillView;
|
|
UIView *_checkShortFragment;
|
|
UIView *_checkLongFragment;
|
|
}
|
|
@end
|
|
|
|
@implementation TGCheckButtonView
|
|
|
|
static CGAffineTransform TGCheckButtonDefaultTransform;
|
|
|
|
- (instancetype)initWithStyle:(TGCheckButtonStyle)style
|
|
{
|
|
CGSize size = CGSizeMake(32.0f, 32.0f);
|
|
if (style == TGCheckButtonStyleGallery)
|
|
size = CGSizeMake(42.0f, 42.0f);
|
|
|
|
self = [super initWithFrame:CGRectMake(0, 0, size.width, size.height)];
|
|
if (self != nil)
|
|
{
|
|
static dispatch_once_t onceToken;
|
|
static NSMutableDictionary *backgroundImages;
|
|
static NSMutableDictionary *fillImages;
|
|
dispatch_once(&onceToken, ^
|
|
{
|
|
TGCheckButtonDefaultTransform = CGAffineTransformMakeRotation(-M_PI_4);
|
|
backgroundImages = [[NSMutableDictionary alloc] init];
|
|
fillImages = [[NSMutableDictionary alloc] init];
|
|
});
|
|
|
|
bool borderOnTop = false;
|
|
CGFloat insideInset = 0.0f;
|
|
switch (style)
|
|
{
|
|
case TGCheckButtonStyleGallery:
|
|
{
|
|
insideInset = 3.5f;
|
|
borderOnTop = true;
|
|
}
|
|
|
|
case TGCheckButtonStyleMedia:
|
|
{
|
|
insideInset = 4.0f;
|
|
borderOnTop = true;
|
|
}
|
|
break;
|
|
|
|
case TGCheckButtonStyleBar:
|
|
{
|
|
insideInset = 2.0f;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
insideInset = 5.0f;
|
|
}
|
|
break;
|
|
}
|
|
|
|
UIImage *backgroundImage = backgroundImages[@(style)];
|
|
if (backgroundImage == nil)
|
|
{
|
|
switch (style)
|
|
{
|
|
case TGCheckButtonStyleGallery:
|
|
{
|
|
CGRect rect = CGRectMake(0, 0, size.width, size.height);
|
|
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0);
|
|
CGContextRef context = UIGraphicsGetCurrentContext();
|
|
CGContextSetShadowWithColor(context, CGSizeZero, 2.5f, [UIColor colorWithWhite:0.0f alpha:0.22f].CGColor);
|
|
CGContextSetLineWidth(context, 1.5f);
|
|
CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
|
|
CGContextStrokeEllipseInRect(context, CGRectInset(rect, insideInset + 0.5f, insideInset + 0.5f));
|
|
|
|
backgroundImage = UIGraphicsGetImageFromCurrentImageContext();
|
|
UIGraphicsEndImageContext();
|
|
}
|
|
break;
|
|
|
|
case TGCheckButtonStyleMedia:
|
|
{
|
|
CGRect rect = CGRectMake(0, 0, size.width, size.height);
|
|
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0);
|
|
CGContextRef context = UIGraphicsGetCurrentContext();
|
|
CGContextSetShadowWithColor(context, CGSizeZero, 2.5f, [UIColor colorWithWhite:0.0f alpha:0.22f].CGColor);
|
|
CGContextSetLineWidth(context, 1.5f);
|
|
CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
|
|
CGContextStrokeEllipseInRect(context, CGRectInset(rect, insideInset + 0.5f, insideInset + 0.5f));
|
|
|
|
backgroundImage = UIGraphicsGetImageFromCurrentImageContext();
|
|
UIGraphicsEndImageContext();
|
|
}
|
|
break;
|
|
|
|
case TGCheckButtonStyleBar:
|
|
{
|
|
CGRect rect = CGRectMake(0, 0, size.width, size.height);
|
|
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0);
|
|
CGContextRef context = UIGraphicsGetCurrentContext();
|
|
CGContextSetLineWidth(context, 1.0f);
|
|
CGContextSetStrokeColorWithColor(context, TGColorWithHex(0xcacacf).CGColor);
|
|
CGContextStrokeEllipseInRect(context, CGRectInset(rect, insideInset + 0.5f, insideInset + 0.5f));
|
|
|
|
backgroundImage = UIGraphicsGetImageFromCurrentImageContext();
|
|
UIGraphicsEndImageContext();
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
CGRect rect = CGRectMake(0, 0, size.width, size.height);
|
|
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0);
|
|
CGContextRef context = UIGraphicsGetCurrentContext();
|
|
CGContextSetLineWidth(context, 1.0f);
|
|
CGContextSetStrokeColorWithColor(context, TGColorWithHex(0xcacacf).CGColor);
|
|
CGContextStrokeEllipseInRect(context, CGRectInset(rect, insideInset + 0.5f, insideInset + 0.5f));
|
|
|
|
backgroundImage = UIGraphicsGetImageFromCurrentImageContext();
|
|
UIGraphicsEndImageContext();
|
|
}
|
|
break;
|
|
}
|
|
|
|
backgroundImages[@(style)] = backgroundImage;
|
|
}
|
|
|
|
UIImage *fillImage = fillImages[@(style)];
|
|
if (fillImage == nil)
|
|
{
|
|
CGRect rect = CGRectMake(0, 0, size.width, size.height);
|
|
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0);
|
|
CGContextRef context = UIGraphicsGetCurrentContext();
|
|
CGContextSetFillColorWithColor(context, TGColorWithHex(0x29c519).CGColor);
|
|
CGContextFillEllipseInRect(context, CGRectInset(rect, insideInset, insideInset));
|
|
|
|
fillImage = UIGraphicsGetImageFromCurrentImageContext();
|
|
UIGraphicsEndImageContext();
|
|
|
|
fillImages[@(style)] = fillImage;
|
|
}
|
|
|
|
_style = style;
|
|
_size = size;
|
|
_borderOnTop = borderOnTop;
|
|
_fillImage = fillImage;
|
|
|
|
_wrapperView = [[UIView alloc] initWithFrame:self.bounds];
|
|
_wrapperView.userInteractionEnabled = false;
|
|
[self addSubview:_wrapperView];
|
|
|
|
_checkBackground = [[CALayer alloc] init];
|
|
_checkBackground.contents = (__bridge id)(backgroundImage.CGImage);
|
|
_checkBackground.frame = CGRectMake(0.0f, 0.0f, size.width, size.height);
|
|
|
|
[_wrapperView.layer addSublayer:_checkBackground];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)_createCheckButtonDetailsIfNeeded
|
|
{
|
|
if (_checkFillView != nil)
|
|
return;
|
|
|
|
if (_borderOnTop)
|
|
[_checkBackground removeFromSuperlayer];
|
|
|
|
_checkFillView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, _size.width, _size.height)];
|
|
_checkFillView.alpha = 0.0f;
|
|
_checkFillView.image = _fillImage;
|
|
_checkFillView.transform = CGAffineTransformMakeScale(0.01f, 0.01f);
|
|
[_wrapperView addSubview:_checkFillView];
|
|
|
|
_checkView = [[UIView alloc] initWithFrame:CGRectInset(self.bounds, 4, 4)];
|
|
_checkView.alpha = 0.0f;
|
|
_checkView.userInteractionEnabled = false;
|
|
_checkView.transform = TGCheckButtonDefaultTransform;
|
|
[_wrapperView addSubview:_checkView];
|
|
|
|
CGRect shortFragmentFrame = CGRectMake(6.5f, 8.5f, 1.5f, 6.0f);
|
|
CGRect longFragmentFrame = CGRectMake(7.5f, 13.0f, 11.0f, 1.5f);
|
|
|
|
if (_style == TGCheckButtonStyleGallery)
|
|
{
|
|
shortFragmentFrame = CGRectMake(9.0f, 12.5f, 2.0f, 8.0f);
|
|
longFragmentFrame = CGRectMake(9.5f, 18.5f, 17.0f, 2.0f);
|
|
}
|
|
|
|
_checkShortFragment = [[UIView alloc] init];
|
|
_checkShortFragment.backgroundColor = [UIColor whiteColor];
|
|
_checkShortFragment.layer.anchorPoint = CGPointMake(0.5f, 0);
|
|
_checkShortFragment.frame = shortFragmentFrame;
|
|
_checkShortFragment.transform = CGAffineTransformMakeScale(1.0f, 0.0f);
|
|
[_checkView addSubview:_checkShortFragment];
|
|
|
|
_checkLongFragment = [[UIView alloc] init];
|
|
_checkLongFragment.backgroundColor = [UIColor whiteColor];
|
|
_checkLongFragment.layer.anchorPoint = CGPointMake(0, 0.5f);
|
|
_checkLongFragment.frame = longFragmentFrame;
|
|
_checkLongFragment.transform = CGAffineTransformMakeScale(0.0f, 1.0f);
|
|
[_checkView addSubview:_checkLongFragment];
|
|
|
|
if (_borderOnTop)
|
|
[_wrapperView.layer addSublayer:_checkBackground];
|
|
}
|
|
|
|
- (void)setSelected:(bool)selected animated:(bool)animated
|
|
{
|
|
[self setSelected:selected animated:animated bump:false];
|
|
}
|
|
|
|
- (void)setSelected:(bool)selected animated:(bool)animated bump:(bool)bump
|
|
{
|
|
if (selected)
|
|
[self _createCheckButtonDetailsIfNeeded];
|
|
|
|
if (animated && bump)
|
|
[self setWrapperScale:selected ? 0.77f : 0.87f animated:false];
|
|
|
|
static dispatch_once_t onceToken;
|
|
static bool inhibitAnimation = false;
|
|
dispatch_once(&onceToken, ^
|
|
{
|
|
inhibitAnimation = ([[[UIDevice currentDevice] systemVersion] compare:@"7" options:NSNumericSearch] == NSOrderedAscending);
|
|
});
|
|
|
|
if (inhibitAnimation)
|
|
animated = false;
|
|
|
|
if (animated)
|
|
{
|
|
if (self.selected == selected)
|
|
return;
|
|
|
|
if (bump)
|
|
{
|
|
if (selected)
|
|
_checkFillView.transform = CGAffineTransformIdentity;
|
|
}
|
|
else
|
|
{
|
|
if (selected)
|
|
_checkFillView.transform = CGAffineTransformMakeScale(0.01f, 0.01f);
|
|
else
|
|
_checkFillView.transform = CGAffineTransformIdentity;
|
|
}
|
|
|
|
[UIView animateWithDuration:0.19f animations:^
|
|
{
|
|
_checkFillView.alpha = selected ? 1.0f : 0.0f;
|
|
if (!bump || !selected)
|
|
_checkFillView.transform = selected ? CGAffineTransformIdentity : CGAffineTransformMakeScale(0.01f, 0.01f);
|
|
}];
|
|
|
|
if (selected)
|
|
{
|
|
CGFloat duration = 0.4f;
|
|
CGFloat damping = 0.35f;
|
|
CGFloat initialVelocity = 0.8f;
|
|
if (bump)
|
|
{
|
|
duration = 0.5f;
|
|
damping = 0.4f;
|
|
initialVelocity = 0.6f;
|
|
}
|
|
|
|
[UIView animateWithDuration:duration delay:0.0f usingSpringWithDamping:damping initialSpringVelocity:initialVelocity options:UIViewAnimationOptionBeginFromCurrentState animations:^
|
|
{
|
|
_wrapperView.transform = CGAffineTransformIdentity;
|
|
} completion:nil];
|
|
|
|
_checkView.alpha = 1.0f;
|
|
_checkShortFragment.transform = CGAffineTransformMakeScale(1.0f, 0.0f);
|
|
_checkLongFragment.transform = CGAffineTransformMakeScale(0.0f, 1.0f);
|
|
|
|
[UIView animateKeyframesWithDuration:0.21f delay:0.0f options:kNilOptions animations:^
|
|
{
|
|
[UIView addKeyframeWithRelativeStartTime:0.0f relativeDuration:0.333f animations:^
|
|
{
|
|
_checkShortFragment.transform = CGAffineTransformIdentity;
|
|
}];
|
|
|
|
[UIView addKeyframeWithRelativeStartTime:0.333f relativeDuration:0.666f animations:^
|
|
{
|
|
_checkLongFragment.transform = CGAffineTransformIdentity;
|
|
}];
|
|
} completion:nil];
|
|
}
|
|
else
|
|
{
|
|
CGFloat duration = 0.17f;
|
|
if (bump)
|
|
duration = 0.15f;
|
|
|
|
[UIView animateWithDuration:duration animations:^
|
|
{
|
|
_checkView.transform = CGAffineTransformScale(_checkView.transform, 0.01f, 0.01f);
|
|
_checkView.alpha = 0.0f;
|
|
|
|
if (bump)
|
|
_wrapperView.transform = CGAffineTransformIdentity;
|
|
} completion:^(__unused BOOL finished)
|
|
{
|
|
_checkView.transform = TGCheckButtonDefaultTransform;
|
|
}];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_checkFillView.alpha = selected ? 1.0f : 0.0f;
|
|
_checkFillView.transform = selected ? CGAffineTransformIdentity : CGAffineTransformMakeScale(0.1f, 0.1f);
|
|
|
|
_checkView.alpha = selected ? 1.0f : 0.0f;
|
|
_checkView.transform = TGCheckButtonDefaultTransform;
|
|
_checkShortFragment.transform = CGAffineTransformIdentity;
|
|
_checkLongFragment.transform = CGAffineTransformIdentity;
|
|
}
|
|
|
|
super.selected = selected;
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
- (void)setWrapperScale:(CGFloat)scale animated:(bool)animated
|
|
{
|
|
void (^change)(void) = ^
|
|
{
|
|
_wrapperView.transform = CGAffineTransformMakeScale(scale, scale);
|
|
};
|
|
|
|
if (animated)
|
|
[UIView animateWithDuration:0.12 delay:0 options:UIViewAnimationOptionAllowAnimatedContent animations:change completion:nil];
|
|
else
|
|
change();
|
|
}
|
|
|
|
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
|
|
{
|
|
[super touchesBegan:touches withEvent:event];
|
|
[self setWrapperScale:0.85f animated:true];
|
|
}
|
|
|
|
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
|
|
{
|
|
[super touchesEnded:touches withEvent:event];
|
|
[self setWrapperScale:1.0f animated:true];
|
|
}
|
|
|
|
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
|
|
{
|
|
[super touchesCancelled:touches withEvent:event];
|
|
[self setWrapperScale:1.0f animated:true];
|
|
}
|
|
|
|
@end
|