IOS UIswitch 自定义开关
2023-08-30 本文已影响0人
sanguing
有时候我们可能不想或者不用系统提供的UISwitch进行布局, 网上各种要么是swift的要么就是纯模仿的系统样式, 不符合前面的需求. 这里尝试用objective-c编写一个新手demo. 基本还是满足一些特定的需求, 代码质量好坏见谅, 毕竟是刚研究不久.
image.png image.png可调节参数
1、开/关背景色
2、按钮块开/关背景色
3、开关的高度和宽度
4、按钮块开/关图标(可以不显示)
代码
.h文件
#import <UIKit/UIKit.h>
typedef enum {
kNKColorSwitchShapeOval,
kNKColorSwitchShapeRectangle,
kNKColorSwitchShapeRectangleNoCorner
} NKColorSwitchShape;
@interface NKColorSwitch : UIControl <UIGestureRecognizerDelegate>
@property (nonatomic, getter = isOn) BOOL on;
@property (nonatomic, assign) NKColorSwitchShape shape;
@property (nonatomic, strong) UIColor *onTintColor;
@property (nonatomic, strong) UIColor *tintColor;
@property (nonatomic, strong) UIColor *thumbTintColor;
@property (nonatomic, strong) UIColor *thumbOffTintColor;
@property (nonatomic, assign) BOOL shadow;
@property (nonatomic, strong) UIColor *tintBorderColor;
@property (nonatomic, strong) UIColor *onTintBorderColor;
@property (nonatomic, strong) NSString *thumbOnTintImage;
@property (nonatomic, strong) NSString *thumbOffTintImage;
@property (nonatomic, assign) float thumbImageHeight;
@property (nonatomic, assign) float thumbImageWidth;
@end
.m文件
#import "NKColorSwitch.h"
#import <QuartzCore/QuartzCore.h>
static const CGFloat kAnimateDuration = 0.3f;
static const CGFloat kHorizontalAdjustment = 8.0f;
static const CGFloat kRectShapeCornerRadius = 4.0f;
static const CGFloat kThumbShadowOpacity = 0.3f;
static const CGFloat kThumbShadowRadius = 0.5f;
static const CGFloat kSwitchBorderWidth = 1.75f;
static const CGFloat kThumbImageHeight = 25;
static const CGFloat kThumbImageWidth = 25;
@interface NKColorSwitch();
@property (nonatomic, strong) UIView *onBackgroundView;
@property (nonatomic, strong) UIView *offBackgroundView;
@property (nonatomic, strong) UIView *thumbView;
@property (nonatomic, strong) UIImageView *thumbImage;
@end
@implementation NKColorSwitch
@synthesize onBackgroundView = _onBackgroundView;
@synthesize offBackgroundView = _offBackgroundView;
@synthesize thumbView = _thumbView;
@synthesize on = _on;
@synthesize shape = _shape;
@synthesize onTintColor = _onTintColor;
@synthesize tintColor = _tintColor;
@synthesize thumbTintColor = _thumbTintColor;
@synthesize shadow = _shadow;
@synthesize onTintBorderColor = _onTintBorderColor;
@synthesize tintBorderColor = _tintBorderColor;
#pragma mark - View
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:[self roundRect:frame]];
if (self) {
// Initialization code
[self setupUI];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder{
if (self = [super initWithCoder:aDecoder]) {
[self setupUI];
}
return self;
}
- (void)setBounds:(CGRect)bounds{
[super setBounds:[self roundRect:bounds]];
[self setNeedsLayout];
}
- (void)setFrame:(CGRect)frame{
[super setBounds:[self roundRect:frame]];
[self setNeedsLayout];
}
- (CGRect)roundRect:(CGRect)frameOrBounds
{
CGRect newRect = frameOrBounds;
newRect.size.height = frameOrBounds.size.height;
newRect.size.width = frameOrBounds.size.width;
[self updateTagViewLayout:newRect];
return newRect;
}
- (void)layoutSubviews{
[super layoutSubviews];
}
- (void) awakeFromNib{
[super awakeFromNib];
//[self setupUI];
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
- (void)setupUI
{
self.shape = kNKColorSwitchShapeOval;
[self setBackgroundColor:[UIColor clearColor]];
// Background view for ON
self.onBackgroundView = [[UIView alloc] initWithFrame:self.bounds];
[self.onBackgroundView setBackgroundColor:[UIColor colorWithRed:(19.0f/255.0f) green:(121.0f/255.0f) blue:(208.0f/255.0f) alpha:1.0f]];
[self.onBackgroundView.layer setCornerRadius:self.frame.size.height/2];
[self.onBackgroundView.layer setShouldRasterize:YES];
[self.onBackgroundView.layer setRasterizationScale:[UIScreen mainScreen].scale];
[self addSubview:self.onBackgroundView];
// Background view for OFF
self.offBackgroundView = [[UIView alloc] initWithFrame:self.bounds];
[self.offBackgroundView setBackgroundColor:[UIColor whiteColor]];
[self.offBackgroundView.layer setCornerRadius:self.frame.size.height/2];
[self.offBackgroundView.layer setShouldRasterize:YES];
[self.offBackgroundView.layer setRasterizationScale:[UIScreen mainScreen].scale];
[self addSubview:self.offBackgroundView];
// Round switch view
self.thumbView = [[UIView alloc] initWithFrame:CGRectMake(kHorizontalAdjustment, 0, self.frame.size.width/2-kHorizontalAdjustment, self.frame.size.height-kHorizontalAdjustment)];
[self.thumbView setBackgroundColor:[UIColor whiteColor]];
[self.thumbView setUserInteractionEnabled:YES];
[self.thumbView.layer setCornerRadius:(self.frame.size.height-kHorizontalAdjustment)/2];
[self.thumbView.layer setShadowOffset:CGSizeMake(0, 1)];
[self.thumbView.layer setShouldRasterize:YES];
[self.thumbView.layer setShadowOpacity:kThumbShadowOpacity];
[self.thumbView.layer setRasterizationScale:[UIScreen mainScreen].scale];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, kThumbImageWidth, kThumbImageHeight)];
self.thumbImage = imageView;
[self.thumbView addSubview: imageView];
[self addSubview:self.thumbView];
self.shadow = YES;
// Default to OFF position
[self.thumbView setCenter:CGPointMake(self.thumbView.frame.size.width/2, self.frame.size.height/2)];
// Handle Thumb Tap Gesture
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwitchTap:)];
[tapGestureRecognizer setDelegate:self];
[self.thumbView addGestureRecognizer:tapGestureRecognizer];
// Handle Background Tap Gesture
UITapGestureRecognizer *tapBgGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleBgTap:)];
[tapBgGestureRecognizer setDelegate:self];
[self addGestureRecognizer:tapBgGestureRecognizer];
// Handle Thumb Pan Gesture
UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
[panGestureRecognizer setDelegate:self];
[self.thumbView addGestureRecognizer:panGestureRecognizer];
[self setOn:NO];
}
#pragma mark - Accessor
- (BOOL)isOn
{
return _on;
}
- (void)setOn:(BOOL)on
{
if (_on != on)
_on = on;
if (_on)
{
[self.onBackgroundView setAlpha:1.0];
self.offBackgroundView.transform = CGAffineTransformMakeScale(1.0, 1.0);
self.thumbView.center = CGPointMake(self.onBackgroundView.frame.size.width - (self.thumbView.frame.size.width+kHorizontalAdjustment)/2, self.thumbView.center.y);
self.thumbView.backgroundColor = self.thumbTintColor;
if (self.thumbOnTintImage){
self.thumbImage.image = [UIImage imageNamed:self.thumbOnTintImage];
//[self.thumbImage setCenter:CGPointMake((self.thumbView.frame.size.width)/2, self.frame.size.height/2 - imageView.frame.size.height/2)];
}
}
else
{
[self.onBackgroundView setAlpha:1.0];
self.offBackgroundView.transform = CGAffineTransformMakeScale(1.0, 1.0);
self.thumbView.center = CGPointMake((self.thumbView.frame.size.width+kHorizontalAdjustment)/2, self.thumbView.center.y);
self.thumbView.backgroundColor = self.thumbOffTintColor;
if (self.thumbOffTintImage){
self.thumbImage.image = [UIImage imageNamed:self.thumbOffTintImage];
}
}
}
- (void)setOnTintColor:(UIColor *)color
{
if (_onTintColor != color)
_onTintColor = color;
[self.onBackgroundView setBackgroundColor:color];
}
- (void)setOnTintBorderColor:(UIColor *)color
{
if (_onTintBorderColor != color)
_onTintBorderColor = color;
[self.onBackgroundView.layer setBorderColor:color.CGColor];
if (color)
[self.onBackgroundView.layer setBorderWidth:kSwitchBorderWidth];
else
[self.onBackgroundView.layer setBorderWidth:0.0];
}
- (void)setTintColor:(UIColor *)color
{
if (_tintColor != color)
_tintColor = color;
[self.offBackgroundView setBackgroundColor:color];
}
- (void)setTintBorderColor:(UIColor *)color
{
if (_tintBorderColor != color)
_tintBorderColor = color;
[self.offBackgroundView.layer setBorderColor:color.CGColor];
if (color)
[self.offBackgroundView.layer setBorderWidth:kSwitchBorderWidth];
else
[self.offBackgroundView.layer setBorderWidth:0.0];
}
- (void)setThumbTintColor:(UIColor *)color
{
if (_thumbTintColor != color)
_thumbTintColor = color;
[self.thumbView setBackgroundColor:color];
}
- (void)setThumbOffTintColor:(UIColor *)thumbOffTintColor{
if (_thumbOffTintColor != thumbOffTintColor)
_thumbOffTintColor = thumbOffTintColor;
}
- (void)setThumbImageHeight:(float)thumbImageHeight{
if (_thumbImageHeight != thumbImageHeight)
_thumbImageHeight = thumbImageHeight;
CGRect frame = self.thumbImage.frame;
frame.size.height = thumbImageHeight;
self.thumbImage.frame = frame;
}
- (void)setThumbImageWidth:(float)thumbImageWidth{
if (_thumbImageWidth != thumbImageWidth)
_thumbImageWidth = thumbImageWidth;
CGRect frame = self.thumbImage.frame;
frame.size.width = thumbImageWidth;
self.thumbImage.frame = frame;
}
- (void)setShape:(NKColorSwitchShape)newShape
{
if (_shape != newShape)
_shape = newShape;
if (newShape == kNKColorSwitchShapeOval)
{
[self.onBackgroundView.layer setCornerRadius:self.frame.size.height/2];
[self.offBackgroundView.layer setCornerRadius:self.frame.size.height/2];
[self.thumbView.layer setCornerRadius:(self.frame.size.height-kHorizontalAdjustment)/2];
}
else if (newShape == kNKColorSwitchShapeRectangle)
{
[self.onBackgroundView.layer setCornerRadius:kRectShapeCornerRadius];
[self.offBackgroundView.layer setCornerRadius:kRectShapeCornerRadius];
[self.thumbView.layer setCornerRadius:kRectShapeCornerRadius];
}
else if (newShape == kNKColorSwitchShapeRectangleNoCorner)
{
[self.onBackgroundView.layer setCornerRadius:0];
[self.offBackgroundView.layer setCornerRadius:0];
[self.thumbView.layer setCornerRadius:0];
}
}
- (void)setShadow:(BOOL)showShadow
{
if (_shadow != showShadow)
_shadow = showShadow;
if (showShadow)
{
[self.thumbView.layer setShadowOffset:CGSizeMake(0, 1)];
[self.thumbView.layer setShadowRadius:kThumbShadowRadius];
[self.thumbView.layer setShadowOpacity:kThumbShadowOpacity];
}
else
{
[self.thumbView.layer setShadowRadius:0.0];
[self.thumbView.layer setShadowOpacity:0.0];
}
}
- (void)setThumbOnTintImage:(NSString *)thumbOnTintImage{
_thumbOnTintImage = thumbOnTintImage;
}
- (void)setThumbOffTintImage:(NSString *)thumbOffTintImage{
_thumbOffTintImage = thumbOffTintImage;
}
#pragma mark - Animation
- (void)animateToDestination:(CGPoint)centerPoint withDuration:(CGFloat)duration switch:(BOOL)on
{
[UIView animateWithDuration:duration
delay:0.0f
options:UIViewAnimationOptionCurveEaseOut
animations:^{
self.thumbView.center = centerPoint;
if (on)
{
[self.onBackgroundView setAlpha:1.0];
self.thumbView.backgroundColor = self.thumbTintColor;
if (self.thumbOnTintImage){
self.thumbImage.image = [UIImage imageNamed:self.thumbOnTintImage];
}
}
else
{
[self.onBackgroundView setAlpha:1.0];
self.thumbView.backgroundColor = self.thumbOffTintColor;
if (self.thumbOffTintImage){
self.thumbImage.image = [UIImage imageNamed:self.thumbOffTintImage];
}
}
}
completion:^(BOOL finished) {
if (finished)
{
[self updateSwitch:on];
}
}];
[UIView animateWithDuration:0
delay:0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
if (on)
{
self.offBackgroundView.transform = CGAffineTransformMakeScale(0.0, 0.0);
}
else
{
self.offBackgroundView.transform = CGAffineTransformMakeScale(1.0, 1.0);
}
}
completion:^(BOOL finished) {
}];
}
#pragma mark - Gesture Recognizers
- (void)handlePan:(UIPanGestureRecognizer *)recognizer
{
CGPoint translation = [recognizer translationInView:self.thumbView];
// Check the new center to see if within the boud
CGPoint newCenter = CGPointMake(recognizer.view.center.x + translation.x,
recognizer.view.center.y);
if (newCenter.x < (recognizer.view.frame.size.width+kHorizontalAdjustment)/2 || newCenter.x > self.onBackgroundView.frame.size.width-(recognizer.view.frame.size.width+kHorizontalAdjustment)/2)
{
// New center is Out of bound. Animate to left or right position
if(recognizer.state == UIGestureRecognizerStateBegan ||
recognizer.state == UIGestureRecognizerStateChanged)
{
CGPoint velocity = [recognizer velocityInView:self.thumbView];
if (velocity.x >= 0)
{
// Animate move to right
[self animateToDestination:CGPointMake(self.onBackgroundView.frame.size.width - (self.thumbView.frame.size.width+kHorizontalAdjustment)/2, recognizer.view.center.y) withDuration:kAnimateDuration switch:YES];
}
else
{
// Animate move to left
[self animateToDestination:CGPointMake((self.thumbView.frame.size.width+kHorizontalAdjustment)/2, recognizer.view.center.y) withDuration:kAnimateDuration switch:NO];
}
}
return;
}
// Only allow vertical pan
recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x,
recognizer.view.center.y);
[recognizer setTranslation:CGPointMake(0, 0) inView:self.thumbView];
CGPoint velocity = [recognizer velocityInView:self.thumbView];
if(recognizer.state == UIGestureRecognizerStateEnded)
{
if (velocity.x >= 0)
{
if (recognizer.view.center.x < self.onBackgroundView.frame.size.width - (self.thumbView.frame.size.width+kHorizontalAdjustment)/2)
{
// Animate move to right
[self animateToDestination:CGPointMake(self.onBackgroundView.frame.size.width - (self.thumbView.frame.size.width+kHorizontalAdjustment)/2, recognizer.view.center.y) withDuration:kAnimateDuration switch:YES];
}
}
else
{
// Animate move to left
[self animateToDestination:CGPointMake((self.thumbView.frame.size.width+kHorizontalAdjustment)/2, recognizer.view.center.y) withDuration:kAnimateDuration switch:NO];
}
}
}
- (void)handleSwitchTap:(UIPanGestureRecognizer *)recognizer
{
if (recognizer.state == UIGestureRecognizerStateEnded)
{
if (self.isOn)
{
// Animate move to left
[self animateToDestination:CGPointMake((self.thumbView.frame.size.width+kHorizontalAdjustment)/2, recognizer.view.center.y) withDuration:kAnimateDuration switch:NO];
}
else
{
// Animate move to right
[self animateToDestination:CGPointMake(self.onBackgroundView.frame.size.width - (self.thumbView.frame.size.width+kHorizontalAdjustment)/2, recognizer.view.center.y) withDuration:kAnimateDuration switch:YES];
}
}
}
- (void)handleBgTap:(UIPanGestureRecognizer *)recognizer
{
if (recognizer.state == UIGestureRecognizerStateEnded)
{
if (self.isOn)
{
// Animate move to left
[self animateToDestination:CGPointMake((self.thumbView.frame.size.width+kHorizontalAdjustment)/2, self.thumbView.center.y) withDuration:kAnimateDuration switch:NO];
}
else
{
// Animate move to right
[self animateToDestination:CGPointMake(self.onBackgroundView.frame.size.width - (self.thumbView.frame.size.width+kHorizontalAdjustment)/2, self.thumbView.center.y) withDuration:kAnimateDuration switch:YES];
}
}
}
#pragma mark -
- (void)updateTagViewLayout:(CGRect)frameOrBounds
{
float height = frameOrBounds.size.height-kHorizontalAdjustment;
float width = frameOrBounds.size.width/2-kHorizontalAdjustment;
self.onBackgroundView.frame = frameOrBounds;
self.offBackgroundView.frame = frameOrBounds;
CGRect frame = self.thumbView.frame;
frame.size.height = height;
frame.size.width = width;
self.thumbView.frame = frame;
[self.thumbView setCenter:CGPointMake((self.thumbView.frame.size.width+kHorizontalAdjustment)/2, frameOrBounds.size.height/2)];
[self.thumbImage setCenter:CGPointMake((self.thumbView.frame.size.width)/2, (frameOrBounds.size.height-kHorizontalAdjustment)/2)];
}
- (void)updateSwitch:(BOOL)on
{
if (_on == YES){
_on = NO;
}else if (_on == NO){
_on = YES;
}
[self sendActionsForControlEvents:UIControlEventValueChanged];
}