美文网首页
IOS UIswitch 自定义开关

IOS UIswitch 自定义开关

作者: sanguing | 来源:发表于2023-08-30 09:31 被阅读0次
    有时候我们可能不想或者不用系统提供的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];
    }
    

    相关文章

      网友评论

          本文标题:IOS UIswitch 自定义开关

          本文链接:https://www.haomeiwen.com/subject/irnomdtx.html