Instantly share code, notes, and snippets.
Created
January 18, 2012 16:20
-
Star
0
(0)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
Save SpacyRicochet/1633825 to your computer and use it in GitHub Desktop.
Trying to fix double tap bug.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// MAConfirmButton.m | |
// | |
// Created by Mike on 11-03-28. | |
// Copyright 2011 Mike Ahmarani. All rights reserved. | |
// | |
#import "MAConfirmButton.h" | |
#import "UIColor-Expanded.h" | |
#define kHeight 26.0 | |
#define kPadding 20.0 | |
#define kFontSize 14.0 | |
@interface MAConfirmButton () | |
@property (nonatomic, copy) NSString *title; | |
@property (nonatomic, copy) NSString *confirm; | |
@property (nonatomic, copy) NSString *disabled; | |
@property (nonatomic, retain) UIColor *tint; | |
- (void)toggle; | |
- (void)setupLayers; | |
- (void)cancel; | |
- (void)lighten; | |
- (void)darken; | |
@end | |
@implementation MAConfirmButton | |
@synthesize title, confirm, disabled, tint, toggleAnimation; | |
- (void)dealloc{ | |
[title release]; | |
[confirm release]; | |
[disabled release]; | |
[tint release]; | |
[super dealloc]; | |
} | |
+ (MAConfirmButton *)buttonWithTitle:(NSString *)titleString confirm:(NSString *)confirmString{ | |
MAConfirmButton *button = [[[super alloc] initWithTitle:titleString confirm:confirmString] autorelease]; | |
return button; | |
} | |
+ (MAConfirmButton *)buttonWithDisabledTitle:(NSString *)disabledString{ | |
MAConfirmButton *button = [[[super alloc] initWithDisabledTitle:disabledString] autorelease]; | |
return button; | |
} | |
- (id)initWithDisabledTitle:(NSString *)disabledString{ | |
self = [super initWithFrame:CGRectZero]; | |
if(self != nil){ | |
disabled = [disabledString retain]; | |
toggleAnimation = MAConfirmButtonToggleAnimationLeft; | |
self.layer.needsDisplayOnBoundsChange = YES; | |
CGSize size = [disabled sizeWithFont:[UIFont boldSystemFontOfSize:kFontSize]]; | |
CGRect r = self.frame; | |
r.size.height = kHeight; | |
r.size.width = size.width+kPadding; | |
self.frame = r; | |
[self setTitle:disabled forState:UIControlStateNormal]; | |
[self setTitleColor:[UIColor colorWithWhite:0.6 alpha:1] forState:UIControlStateNormal]; | |
[self setTitleShadowColor:[UIColor colorWithWhite:1 alpha:1] forState:UIControlStateNormal]; | |
self.titleLabel.textAlignment = UITextAlignmentCenter; | |
self.titleLabel.shadowOffset = CGSizeMake(0, 1); | |
self.titleLabel.backgroundColor = [UIColor clearColor]; | |
self.titleLabel.font = [UIFont boldSystemFontOfSize:kFontSize]; | |
self.tint = [UIColor colorWithWhite:0.85 alpha:1]; | |
[self setupLayers]; | |
} | |
return self; | |
} | |
- (id)initWithTitle:(NSString *)titleString confirm:(NSString *)confirmString{ | |
self = [super initWithFrame:CGRectZero]; | |
if(self != nil){ | |
self.title = [titleString retain]; | |
self.confirm = [confirmString retain]; | |
toggleAnimation = MAConfirmButtonToggleAnimationLeft; | |
self.layer.needsDisplayOnBoundsChange = YES; | |
CGSize size = [title sizeWithFont:[UIFont boldSystemFontOfSize:kFontSize]]; | |
CGRect r = self.frame; | |
r.size.height = kHeight; | |
r.size.width = size.width+kPadding; | |
self.frame = r; | |
[self setTitle:title forState:UIControlStateNormal]; | |
[self setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; | |
[self setTitleShadowColor:[UIColor colorWithWhite:0 alpha:0.5] forState:UIControlStateNormal]; | |
self.titleLabel.textAlignment = UITextAlignmentCenter; | |
self.titleLabel.shadowOffset = CGSizeMake(0, -1); | |
self.titleLabel.backgroundColor = [UIColor clearColor]; | |
self.titleLabel.font = [UIFont boldSystemFontOfSize:kFontSize]; | |
self.tint = [UIColor colorWithRed:0.220 green:0.357 blue:0.608 alpha:1]; | |
[self setupLayers]; | |
} | |
return self; | |
} | |
- (void)toggle{ | |
self.titleLabel.alpha = 0; | |
CGSize size; | |
if(disabled){ | |
[self setTitle:disabled forState:UIControlStateNormal]; | |
[self setTitleColor:[UIColor colorWithWhite:0.6 alpha:1] forState:UIControlStateNormal]; | |
[self setTitleShadowColor:[UIColor colorWithWhite:1 alpha:1] forState:UIControlStateNormal]; | |
self.titleLabel.shadowOffset = CGSizeMake(0, 1); | |
size = [disabled sizeWithFont:[UIFont boldSystemFontOfSize:kFontSize]]; | |
}else if(selected){ | |
[self setTitle:confirm forState:UIControlStateNormal]; | |
size = [confirm sizeWithFont:[UIFont boldSystemFontOfSize:kFontSize]]; | |
}else{ | |
[self setTitle:title forState:UIControlStateNormal]; | |
size = [title sizeWithFont:[UIFont boldSystemFontOfSize:kFontSize]]; | |
} | |
size.width += kPadding; | |
float offset = size.width - self.frame.size.width; | |
self.userInteractionEnabled = NO; | |
[CATransaction begin]; | |
[CATransaction setAnimationDuration:0.25]; | |
[CATransaction setCompletionBlock:^{ | |
//Readjust button frame for new touch area, move layers back now that animation is done | |
[CATransaction setCompletionBlock:^{ | |
self.userInteractionEnabled = YES; | |
}]; | |
CGRect frameRect = self.frame; | |
switch (self.toggleAnimation) { | |
case MAConfirmButtonToggleAnimationLeft: | |
frameRect.origin.x = frameRect.origin.x - offset; | |
break; | |
case MAConfirmButtonToggleAnimationRight: | |
break; | |
default: | |
break; | |
} | |
frameRect.size.width = frameRect.size.width + offset; | |
self.frame = frameRect; | |
[CATransaction setDisableActions:YES]; | |
for(CALayer *layer in self.layer.sublayers){ | |
CGRect rect = layer.frame; | |
switch (self.toggleAnimation) { | |
case MAConfirmButtonToggleAnimationLeft: | |
rect.origin.x = rect.origin.x+offset; | |
break; | |
case MAConfirmButtonToggleAnimationRight: | |
break; | |
default: | |
break; | |
} | |
layer.frame = rect; | |
} | |
[CATransaction commit]; | |
self.titleLabel.alpha = 1; | |
[self setNeedsLayout]; | |
}]; | |
UIColor *greenColor = [UIColor colorWithRed:0.439 green:0.741 blue:0.314 alpha:1.]; | |
//Animate color change | |
CABasicAnimation *colorAnimation = [CABasicAnimation animationWithKeyPath:@"backgroundColor"]; | |
colorAnimation.removedOnCompletion = NO; | |
colorAnimation.fillMode = kCAFillModeForwards; | |
if(disabled){ | |
colorAnimation.fromValue = (id)greenColor.CGColor; | |
colorAnimation.toValue = (id)[UIColor colorWithWhite:0.85 alpha:1].CGColor; | |
}else{ | |
colorAnimation.fromValue = selected ? (id)tint.CGColor : (id)greenColor.CGColor; | |
colorAnimation.toValue = selected ? (id)greenColor.CGColor : (id)tint.CGColor; | |
} | |
[colorLayer addAnimation:colorAnimation forKey:@"colorAnimation"]; | |
//Animate layer scaling | |
for(CALayer *layer in self.layer.sublayers){ | |
CGRect rect = layer.frame; | |
switch (self.toggleAnimation) { | |
case MAConfirmButtonToggleAnimationLeft: | |
rect.origin.x = rect.origin.x-offset; | |
break; | |
case MAConfirmButtonToggleAnimationRight: | |
break; | |
default: | |
break; | |
} | |
rect.size.width = rect.size.width+offset; | |
layer.frame = rect; | |
} | |
[CATransaction commit]; | |
[self setNeedsDisplay]; | |
} | |
- (void)setupLayers{ | |
CAGradientLayer *bevelLayer = [CAGradientLayer layer]; | |
bevelLayer.frame = CGRectMake(0, 0, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame)); | |
bevelLayer.colors = [NSArray arrayWithObjects:(id)[UIColor colorWithWhite:0 alpha:0.5].CGColor, [UIColor whiteColor].CGColor, nil]; | |
bevelLayer.cornerRadius = 4.0; | |
bevelLayer.needsDisplayOnBoundsChange = YES; | |
colorLayer = [CALayer layer]; | |
colorLayer.frame = CGRectMake(0, 1, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame)-2); | |
colorLayer.borderColor = [UIColor colorWithWhite:0 alpha:0.1].CGColor; | |
colorLayer.backgroundColor = tint.CGColor; | |
colorLayer.borderWidth = 1.0; | |
colorLayer.cornerRadius = 4.0; | |
colorLayer.needsDisplayOnBoundsChange = YES; | |
CAGradientLayer *colorGradient = [CAGradientLayer layer]; | |
colorGradient.frame = CGRectMake(0, 1, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame)-2); | |
colorGradient.colors = [NSArray arrayWithObjects:(id)[UIColor colorWithWhite:1 alpha:0.1].CGColor, [UIColor colorWithWhite:0.2 alpha:0.1].CGColor , nil]; | |
colorGradient.locations = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0.0], [NSNumber numberWithFloat:1.0], nil]; | |
colorGradient.cornerRadius = 4.0; | |
colorGradient.needsDisplayOnBoundsChange = YES; | |
[self.layer addSublayer:bevelLayer]; | |
[self.layer addSublayer:colorLayer]; | |
[self.layer addSublayer:colorGradient]; | |
[self bringSubviewToFront:self.titleLabel]; | |
} | |
- (void)setSelected:(BOOL)s{ | |
selected = s; | |
[self toggle]; | |
} | |
- (void)disableWithTitle:(NSString *)disabledString{ | |
self.disabled = [disabledString retain]; | |
[self toggle]; | |
} | |
- (void)setAnchor:(CGPoint)anchor{ | |
//Top-right point of the view (MUST BE SET LAST) | |
CGRect rect = self.frame; | |
rect.origin = CGPointMake(anchor.x - rect.size.width, anchor.y); | |
self.frame = rect; | |
} | |
- (void)setTintColor:(UIColor *)color{ | |
self.tint = [UIColor colorWithHue:color.hue saturation:color.saturation+0.15 brightness:color.brightness alpha:1]; | |
colorLayer.backgroundColor = tint.CGColor; | |
[self setNeedsDisplay]; | |
} | |
- (void)darken{ | |
darkenLayer = [CALayer layer]; | |
darkenLayer.frame = CGRectMake(0, 0, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame)); | |
darkenLayer.backgroundColor = [UIColor colorWithWhite:0 alpha:0.2].CGColor; | |
darkenLayer.cornerRadius = 4.0; | |
darkenLayer.needsDisplayOnBoundsChange = YES; | |
[self.layer addSublayer:darkenLayer]; | |
} | |
- (void)lighten{ | |
if(darkenLayer){ | |
[darkenLayer removeFromSuperlayer]; | |
darkenLayer = nil; | |
} | |
} | |
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ | |
if (self.userInteractionEnabled) { | |
if(!disabled && !confirmed){ | |
[self darken]; | |
} | |
[super touchesBegan:touches withEvent:event]; | |
} | |
} | |
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{ | |
if (self.userInteractionEnabled) { | |
if(!disabled && !confirmed){ | |
if(!CGRectContainsPoint(self.frame, [[touches anyObject] locationInView:self.superview])){ //TouchUpOutside (Cancelled Touch) | |
[self lighten]; | |
[super touchesCancelled:touches withEvent:event]; | |
}else if(selected){ | |
[self lighten]; | |
confirmed = YES; | |
[cancelOverlay removeFromSuperview]; | |
cancelOverlay = nil; | |
[super touchesEnded:touches withEvent:event]; | |
}else{ | |
[self lighten]; | |
self.selected = YES; | |
cancelOverlay = [UIButton buttonWithType:UIButtonTypeCustom]; | |
[cancelOverlay setFrame:CGRectMake(0, 0, 1024, 1024)]; | |
[cancelOverlay addTarget:self action:@selector(cancel) forControlEvents:UIControlEventTouchDown]; | |
[self.superview addSubview:cancelOverlay]; | |
[self.superview bringSubviewToFront:self]; | |
} | |
} | |
} | |
} | |
- (void)cancel{ | |
if(cancelOverlay){ | |
[cancelOverlay removeFromSuperview]; | |
cancelOverlay = nil; | |
} | |
self.selected = NO; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment