自定義 Switch 開關按鈕
阿新 • • 發佈:2019-01-23
#import <UIKit/UIKit.h>
@interface SevenSwitch : UIControl
@property (nonatomic, assign) BOOL on;
@property (nonatomic, strong) UIColor *inactiveColor;
@property (nonatomic, strong) UIColor *activeColor;
@property (nonatomic, strong) UIColor *onColor;
@property (nonatomic, strong) UIColor *borderColor;
@property (nonatomic, strong) UIColor *knobColor;
@property (nonatomic, strong) UIColor *shadowColor;
@property (nonatomic, assign) BOOL isRounded;
@property (nonatomic, strong) UIImage *onImage;
@property (nonatomic, strong) UIImage *offImage;
- (void)setOn:(BOOL)on animated:(BOOL)animated;
- (BOOL)isOn;
@end
#import "SevenSwitch.h"
#import <QuartzCore/QuartzCore.h>
@interface SevenSwitch () {
UIView *background;
UIView *knob;
UIImageView *onImageView;
UIImageView *offImageView;
double startTime;
BOOL isAnimating;
}
@property (nonatomic, strong) UIView *containerView;
- (void)showOn:(BOOL)animated;
- (void)showOff:(BOOL)animated;
- (void)setup;
@end
@implementation SevenSwitch
@synthesize inactiveColor, activeColor, onColor, borderColor, knobColor, shadowColor;
@synthesize onImage, offImage;
@synthesize isRounded;
@synthesize on;
#pragma mark init Methods
- (id)init {
self = [super initWithFrame:CGRectMake(0, 0, 50, 30)];
if (self) {
[self setup];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
[self setup];
}
return self;
}
- (id)initWithFrame:(CGRect)frame
{
// use the default values if CGRectZero frame is set
CGRect initialFrame;
if (CGRectIsEmpty(frame)) {
initialFrame = CGRectMake(0, 0, 50, 30);
}
else {
initialFrame = frame;
}
self = [super initWithFrame:initialFrame];
if (self) {
[self setup];
}
return self;
}
- (void)setup {
// default values
self.on = NO;
self.isRounded = YES;
self.inactiveColor = [UIColor clearColor];
self.activeColor = [UIColor colorWithRed:0.89f green:0.89f blue:0.89f alpha:1.00f];
self.onColor = [UIColor colorWithRed:0.30f green:0.85f blue:0.39f alpha:1.00f];
self.borderColor = [UIColor colorWithRed:0.89f green:0.89f blue:0.91f alpha:1.00f];
self.knobColor = [UIColor whiteColor];
self.shadowColor = [UIColor grayColor];
// background
background = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
background.backgroundColor = [UIColor clearColor];
background.layer.cornerRadius = self.frame.size.height * 0.5;
background.layer.borderColor = self.borderColor.CGColor;
background.layer.borderWidth = 1.0;
background.userInteractionEnabled = NO;
[self addSubview:background];
// images
onImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width - self.frame.size.height, self.frame.size.height)];
// [onImageView setContentMode:UIViewContentModeScaleToFill];
onImageView.alpha = 0;
onImageView.contentMode = UIViewContentModeCenter;
[self addSubview:onImageView];
offImageView = [[UIImageView alloc] initWithFrame:CGRectMake(self.frame.size.height, 0, self.frame.size.width - self.frame.size.height, self.frame.size.height)];
offImageView.alpha = 1.0;
offImageView.contentMode = UIViewContentModeCenter;
[self addSubview:offImageView];
// knob
knob = [[UIView alloc] initWithFrame:CGRectMake(1, 1, self.frame.size.height - 2, self.frame.size.height - 2)];
knob.backgroundColor = self.knobColor;
knob.layer.cornerRadius = (self.frame.size.height * 0.5) - 1;
knob.layer.shadowColor = self.shadowColor.CGColor;
knob.layer.shadowRadius = 2.0;
knob.layer.shadowOpacity = 0.5;
knob.layer.shadowOffset = CGSizeMake(0, 3);
knob.layer.masksToBounds = NO;
knob.userInteractionEnabled = NO;
[self addSubview:knob];
isAnimating = NO;
}
#pragma mark Touch Tracking
- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
[super beginTrackingWithTouch:touch withEvent:event];
// start timer to detect tap later in endTrackingWithTouch:withEvent:
startTime = [[NSDate date] timeIntervalSince1970];
// make the knob larger and animate to the correct color
CGFloat activeKnobWidth = self.bounds.size.height - 2 + 5;
isAnimating = YES;
[UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionCurveEaseOut|UIViewAnimationOptionBeginFromCurrentState animations:^{
if (self.on) {
knob.frame = CGRectMake(self.bounds.size.width - (activeKnobWidth + 1), knob.frame.origin.y, activeKnobWidth, knob.frame.size.height);
background.backgroundColor = self.onColor;
}
else {
knob.frame = CGRectMake(knob.frame.origin.x, knob.frame.origin.y, activeKnobWidth, knob.frame.size.height);
background.backgroundColor = self.activeColor;
}
} completion:^(BOOL finished) {
isAnimating = NO;
}];
return YES;
}
- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
[super continueTrackingWithTouch:touch withEvent:event];
// Get touch location
CGPoint lastPoint = [touch locationInView:self];
// update the switch to the correct visuals depending on if
// they moved their touch to the right or left side of the switch
if (lastPoint.x > self.bounds.size.width * 0.5)
[self showOn:YES];
else
[self showOff:YES];
return YES;
}
- (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
[super endTrackingWithTouch:touch withEvent:event];
// capture time to see if this was a tap action
double endTime = [[NSDate date] timeIntervalSince1970];
double difference = endTime - startTime;
BOOL previousValue = self.on;
// determine if the user tapped the switch or has held it for longer
if (difference <= 0.2) {
CGFloat normalKnobWidth = self.bounds.size.height - 2;
knob.frame = CGRectMake(knob.frame.origin.x, knob.frame.origin.y, normalKnobWidth, knob.frame.size.height);
[self setOn:!self.on animated:YES];
}
else {
// Get touch location
CGPoint lastPoint = [touch locationInView:self];
// update the switch to the correct value depending on if
// their touch finished on the right or left side of the switch
if (lastPoint.x > self.bounds.size.width * 0.5)
[self setOn:YES animated:YES];
else
[self setOn:NO animated:YES];
}
if (previousValue != self.on)
[self sendActionsForControlEvents:UIControlEventValueChanged];
}
- (void)cancelTrackingWithEvent:(UIEvent *)event {
[super cancelTrackingWithEvent:event];
// just animate back to the original value
if (self.on)
[self showOn:YES];
else
[self showOff:YES];
}
- (void)layoutSubviews {
[super layoutSubviews];
if (!isAnimating) {
CGRect frame = self.frame;
// background
background.frame = CGRectMake(0, 0, frame.size.width, frame.size.height);
background.layer.cornerRadius = self.isRounded ? frame.size.height * 0.5 : 2;
// images
onImageView.frame = CGRectMake(0, 0, frame.size.width, frame.size.height);
[onImageView setContentMode:UIViewContentModeScaleAspectFit];
offImageView.frame = CGRectMake(0, 0, frame.size.width, frame.size.height);
[offImageView setContentMode:UIViewContentModeScaleAspectFit];
// knob
CGFloat normalKnobWidth = frame.size.height - 2;
if (self.on)
knob.frame = CGRectMake(frame.size.width - (normalKnobWidth + 1), 1, frame.size.height - 2, normalKnobWidth);
else
knob.frame = CGRectMake(1, 1, normalKnobWidth, normalKnobWidth);
knob.layer.cornerRadius = self.isRounded ? (frame.size.height * 0.5) - 1 : 2;
}
}
#pragma mark Setters
- (void)setInactiveColor:(UIColor *)color {
inactiveColor = color;
if (!self.on && !self.isTracking)
background.backgroundColor = color;
}
- (void)setOnColor:(UIColor *)color {
onColor = color;
if (self.on && !self.isTracking) {
background.backgroundColor = color;
background.layer.borderColor = color.CGColor;
}
}
- (void)setBorderColor:(UIColor *)color {
borderColor = color;
if (!self.on)
background.layer.borderColor = color.CGColor;
}
- (void)setKnobColor:(UIColor *)color {
knobColor = color;
knob.backgroundColor = color;
}
- (void)setShadowColor:(UIColor *)color {
shadowColor = color;
knob.layer.shadowColor = color.CGColor;
}
- (void)setOnImage:(UIImage *)image {
onImage = image;
onImageView.image = image;
}
- (void)setOffImage:(UIImage *)image {
offImage = image;
offImageView.image = image;
}
- (void)setIsRounded:(BOOL)rounded {
isRounded = rounded;
if (rounded) {
background.layer.cornerRadius = self.frame.size.height * 0.5;
knob.layer.cornerRadius = (self.frame.size.height * 0.5) - 1;
}
else {
background.layer.cornerRadius = 2;
knob.layer.cornerRadius = 2;
}
}
- (void)setOn:(BOOL)isOn {
[self setOn:isOn animated:NO];
}
- (void)setOn:(BOOL)isOn animated:(BOOL)animated {
on = isOn;
if (isOn) {
[self showOn:animated];
}
else {
[self showOff:animated];
}
}
#pragma mark Getters
- (BOOL)isOn {
return self.on;
}
#pragma mark State Changes
- (void)showOn:(BOOL)animated {
CGFloat normalKnobWidth = self.bounds.size.height - 2;
CGFloat activeKnobWidth = normalKnobWidth + 5;
if (animated) {
isAnimating = YES;
[UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionCurveEaseOut|UIViewAnimationOptionBeginFromCurrentState animations:^{
if (self.tracking)
knob.frame = CGRectMake(self.bounds.size.width - (activeKnobWidth + 1), knob.frame.origin.y, activeKnobWidth, knob.frame.size.height);
else
knob.frame = CGRectMake(self.bounds.size.width - (normalKnobWidth + 1), knob.frame.origin.y, normalKnobWidth, knob.frame.size.height);
background.backgroundColor = self.onColor;
background.layer.borderColor = self.onColor.CGColor;
onImageView.alpha = 1.0;
offImageView.alpha = 0;
} completion:^(BOOL finished) {
isAnimating = NO;
}];
}
else {
if (self.tracking)
knob.frame = CGRectMake(self.bounds.size.width - (activeKnobWidth + 1), knob.frame.origin.y, activeKnobWidth, knob.frame.size.height);
else
knob.frame = CGRectMake(self.bounds.size.width - (normalKnobWidth + 1), knob.frame.origin.y, normalKnobWidth, knob.frame.size.height);
background.backgroundColor = self.onColor;
background.layer.borderColor = self.onColor.CGColor;
onImageView.alpha = 1.0;
offImageView.alpha = 0;
}
}
- (void)showOff:(BOOL)animated {
CGFloat normalKnobWidth = self.bounds.size.height - 2;
CGFloat activeKnobWidth = normalKnobWidth + 5;
if (animated) {
isAnimating = YES;
[UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionCurveEaseOut|UIViewAnimationOptionBeginFromCurrentState animations:^{
if (self.tracking) {
knob.frame = CGRectMake(1, knob.frame.origin.y, activeKnobWidth, knob.frame.size.height);
background.backgroundColor = self.activeColor;
}
else {
knob.frame = CGRectMake(1, knob.frame.origin.y, normalKnobWidth, knob.frame.size.height);
background.backgroundColor = self.inactiveColor;
}
background.layer.borderColor = self.borderColor.CGColor;
onImageView.alpha = 0;
offImageView.alpha = 1.0;
} completion:^(BOOL finished) {
isAnimating = NO;
}];
}
else {
if (self.tracking) {
knob.frame = CGRectMake(1, knob.frame.origin.y, activeKnobWidth, knob.frame.size.height);
background.backgroundColor = self.activeColor;
}
else {
knob.frame = CGRectMake(1, knob.frame.origin.y, normalKnobWidth, knob.frame.size.height);
background.backgroundColor = self.inactiveColor;
}
background.layer.borderColor = self.borderColor.CGColor;
onImageView.alpha = 0;
offImageView.alpha = 1.0;
}
}
@end