自定义Switch控件

简介: 做iOS开发也有一段时间的了,项目中的开关控件一直都是用的系统级别的,至多就是给UISwitch控件换一个tintColor。这次的UI设计师设计了一个带有动画效果的UISwitch控件。

前言

做iOS开发也有一段时间的了,项目中的开关控件一直都是用的系统级别的,至多就是给UISwitch控件换一个tintColor。这次的UI设计师设计了一个带有动画效果的UISwitch控件。如下图:


一开始为了快速开发就没在在意这个小问题,用的系统的。但是子啊UI做评审的时候说我的这个还原度是不OK的。那怎么办呢,想办法自己写一个吧.....(其实我们也想过用Airbnb的那个开原动画框架的,但是....种种原因吧,没用)。

想法

基本的思路就是现在底部放上一个UIView做底,然后上面做一个UIbutton,实现开关的效果,然后再点击开关的时候出发一下动画效果,从而达到UI的还原度要求。

撸起袖子,就是干 ! ! !

首先我们在.h文件中写下如下的代码:


@protocol  SwitchViewDelegate <NSObject>

- (void)switchView_didChangeValue:(SwitchView *)zpswitch value:(BOOL)value;

@end

@interface SwitchView : UIView

@property (nonatomic, assign) BOOL on;

@property (nonatomic, weak) id<SwitchViewDelegate> delegate;

@end

最上面的SwitchViewDelegate的方法是在我们点击按钮切换当前的选中状态的。on这个属性暴出去的目的方便使用者去设置一开始的初始状态和之后的状态切换。

然后我们去点击.m文件。
我们要在这里声明两个属性:


@interface SwitchView()

@property (nonatomic,strong) UIButton *switchButton;

@property (nonatomic,assign) BOOL isFirst;

@end

switchButton这是用来点击的UIButton控件,就和我们平时创建,初始化没什么区别。
isFirst这个是一个标志位,用来判断是不是第一次显示的问题。
我们把相关的属性声明都弄完了之后就开始正题。

初始化

- (instancetype)initWithFrame:(CGRect)frame{
    self = [super initWithFrame:frame];
    if (self) {
        self.isFirst = YES;
        self.backgroundColor = [UIColor colorWithRed:242/255.0 green:242/255.0 blue:242/255.0 alpha:1];
        self.layer.masksToBounds = YES;
        self.layer.borderColor = [UIColor colorWithRed:218/255.0 green:218/255.0 blue:218/255.0 alpha:1].CGColor;
        self.layer.borderWidth = 1.0f;
        self.layer.cornerRadius = self.bounds.size.height / 2.0;
        self.clipsToBounds = YES;
        [self addSubview:self.switchButton];
        self.switchButton.layer.cornerRadius = self.switchButton.bounds.size.height / 2.0;
    }
    return self;
}
- (UIButton *)switchButton{
    if (!_switchButton) {
        _switchButton = [UIButton buttonWithType:UIButtonTypeCustom];
        _switchButton.frame = CGRectMake(0, 0, self.bounds.size.height, self.bounds.size.height);
        [_switchButton setImage:[UIImage imageNamed:@"Group 8"] forState:UIControlStateNormal];
        [_switchButton setImage:[UIImage imageNamed:@"Group 2"] forState:UIControlStateSelected];
        [_switchButton addTarget:self action:@selector(switcherButtonTouch:) forControlEvents:UIControlEventTouchUpInside];
    }
    return _switchButton;
}

这里就是懒加载了一个UIButton,还有就是设置有了一些圆角的属性。这么设置圆角的属性并不是最佳的办法,但是就是一个Demo示例。所以并没有计较那么多。

交互

在上面你们看到了,我们给button添加了一个点击方法,这里我们就要去实现这个方法

- (void)switcherButtonTouch:(UIButton *)sender{
    self.on = !self.on;
    if (self.delegate && [self.delegate respondsToSelector:@selector(switchView_didChangeValue:value:)]) {
        [self.delegate switchView_didChangeValue:self value:self.on];
    }
}

这里就是在变化button的值得时候,通过delegate方法传到控制器或者相应的superView

动画

- (void)animationSwitcherButton{
    if (self.on) {
        [UIView animateWithDuration:0.5 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
            CABasicAnimation *rotateAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
            rotateAnimation.fromValue = [NSNumber numberWithFloat:-M_PI];
            rotateAnimation.toValue = [NSNumber numberWithFloat:0.0];
            rotateAnimation.duration = 0.45;
            rotateAnimation.cumulative = NO;
            [self.switchButton.layer addAnimation:rotateAnimation forKey:@"rotate"];

            self.backgroundColor = [UIColor colorWithRed:0/255.0 green:141/255.0 blue:150/255.0 alpha:1];
            self.layer.masksToBounds = YES;
            self.layer.borderColor = [UIColor colorWithRed:0/255.0 green:141/255.0 blue:150/255.0 alpha:1].CGColor;
            self.layer.borderWidth = 1.0f;

            self.switchButton.selected = YES;
            self.switchButton.frame = CGRectMake(self.bounds.size.width - self.bounds.size.height, 0, self.bounds.size.height, self.bounds.size.height);
        } completion:^(BOOL finished) {
            self.switchButton.selected = YES;
            self.switchButton.frame = CGRectMake(self.bounds.size.width - self.bounds.size.height, 0, self.bounds.size.height, self.bounds.size.height);
        }];
    }else{
        [UIView animateWithDuration:0.5 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
            CABasicAnimation *rotateAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
            rotateAnimation.toValue = [NSNumber numberWithFloat:-M_PI];
            rotateAnimation.fromValue = [NSNumber numberWithFloat:0.0];
            rotateAnimation.duration = 0.45;
            rotateAnimation.cumulative = NO;
            [self.switchButton.layer addAnimation:rotateAnimation forKey:@"rotate"];
            self.backgroundColor = [UIColor colorWithRed:242/255.0 green:242/255.0 blue:242/255.0 alpha:1];
            self.layer.masksToBounds = YES;
            self.layer.borderColor = [UIColor colorWithRed:218/255.0 green:218/255.0 blue:218/255.0 alpha:1].CGColor;
            self.layer.borderWidth = 1.0f;
            self.switchButton.selected = NO;
            self.switchButton.frame = CGRectMake(0, 0, self.bounds.size.height, self.bounds.size.height);
        } completion:^(BOOL finished) {
            self.switchButton.selected = NO;
           self.switchButton.frame = CGRectMake(0, 0, self.bounds.size.height, self.bounds.size.height);
        }];
    }
}

这里面做了一个旋转的动画和平移的动画。到现在为止你就可以实现基本的要求了。当你从不被选中切换到选中的时候,感觉棒棒哒。但是这个交互只能在点击button的时候会有,和系统的那个UISwitch还是有着一定的区别的。还有就是如果一开始就是选中的状态,现在的代码还不能完全满足。
so

优化一下

1.增加一个手势,让点击这个控件的时候就可以响应变化方法:
我们在上面的那个- (instancetype)initWithFrame:(CGRect)frame方法中添加一个tap手势。

 UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(switcherButtonTouch:)];
[self addGestureRecognizer:tap];

2.让使用者自由的设置on的初始值:

- (void)setOn:(BOOL)on{
    _on = on;
    if (_on && self.isFirst) {
        self.backgroundColor = [UIColor colorWithRed:0/255.0 green:141/255.0 blue:150/255.0 alpha:1];
        self.layer.masksToBounds = YES;
        self.layer.borderColor = [UIColor colorWithRed:0/255.0 green:141/255.0 blue:150/255.0 alpha:1].CGColor;
        self.layer.borderWidth = 1.0f;
        self.switchButton.selected = YES;
        self.switchButton.frame = CGRectMake(self.bounds.size.width - self.bounds.size.height, 0, self.bounds.size.height, self.bounds.size.height);
        self.isFirst = NO;
    }else{
        [self animationSwitcherButton];
        self.isFirst = NO;
    }
}

通过on的值和self.isFirst的联合判断,从而达到优化效果

实现

    SwitchView *switchView1 = [[SwitchView alloc]initWithFrame:CGRectMake(100, 200, 46, 32)];
    switchView1.on = NO;
    switchView1.delegate = self;
    [self.view addSubview:switchView1];

效果

传送门

https://github.com/cAibDe/SwitchView

相关文章
|
7月前
|
JavaScript 前端开发
Bootstrap-Switch开关控件使用指南
Bootstrap-Switch开关控件使用指南
|
5月前
Element UI【实战范例】下拉选择 el-select 的 change 事件传入选中值+自定义参数
Element UI【实战范例】下拉选择 el-select 的 change 事件传入选中值+自定义参数
884 1
|
6月前
|
Java Android开发 开发者
17. 【Android教程】开关控件ToggleButton/Switch
17. 【Android教程】开关控件ToggleButton/Switch
84 2
|
5月前
【亲测有效】Element UI 自定义 Notification 通知样式不生效,设置this.$notify样式不生效问题
【亲测有效】Element UI 自定义 Notification 通知样式不生效,设置this.$notify样式不生效问题
218 0
|
7月前
|
移动开发 JavaScript 小程序
uView Switch 开关选择器
uView Switch 开关选择器
59 1
|
7月前
|
移动开发 JavaScript 小程序
uniapp中组件库丰富的Switch 开关选择器使用方法
uniapp中组件库丰富的Switch 开关选择器使用方法
477 1
|
7月前
MFC自定义button实现颜色控制
MFC自定义button实现颜色控制
easyUI datagarid 编辑状态下的combobox动态赋值
easyUI datagarid 编辑状态下的combobox动态赋值
|
前端开发
switch对按钮进行判断操作
switch对按钮进行判断操作
83 0
写一个原生switch开关按钮
欢迎阅读本博文,本博文主要讲述【写一个原生switch开关按钮】,文字通俗易懂,如有不妥,还请多多指正。
写一个原生switch开关按钮