• 自定义购物数量按钮


    .h
    
    #import <UIKit/UIKit.h>
    
    @protocol PPNumberButtonDelegate <NSObject>
    @optional
    /** 加减按钮点击响应的代理回调*/
    - (void)pp_numberButton:(__kindof UIView *)numberButton number:(NSString *)number;
    @end
    
    IB_DESIGNABLE
    @interface PPNumberButton : UIView
    /**
     *  通过类方法创建一个按钮实例对象
     */
    + (instancetype)numberButtonWithFrame:(CGRect)frame;
    
    /** 加减按钮的Block回调*/
    @property (nonatomic, copy) void(^numberBlock)(NSString *number);
    /** 代理*/
    @property (nonatomic, weak) id<PPNumberButtonDelegate> delegate;
    
    #pragma mark - 自定义样式属性设置
    /** 是否开启抖动动画,默认NO*/
    @property (nonatomic, assign ) IBInspectable BOOL shakeAnimation;
    /** 为YES时,初始化时减号按钮隐藏(饿了么/百度外卖/美团外卖按钮模式),default is NO*/
    @property (nonatomic, assign ) IBInspectable BOOL decreaseHide;
    
    /** 设置边框的颜色,如果没有设置颜色,就没有边框 */
    @property (nonatomic, strong ) IBInspectable UIColor *borderColor;
    
    /** 输入框中的内容 */
    @property (nonatomic, copy   ) NSString *currentNumber;
    /** 输入框中的字体大小 */
    @property (nonatomic, assign ) IBInspectable CGFloat inputFieldFont;
    
    /** 加减按钮的字体大小 */
    @property (nonatomic, assign ) IBInspectable CGFloat buttonTitleFont;
    /** 加按钮背景图片 */
    @property (nonatomic, strong ) IBInspectable UIImage *increaseImage;
    /** 减按钮背景图片 */
    @property (nonatomic, strong ) IBInspectable UIImage *decreaseImage;
    /** 加按钮标题 */
    @property (nonatomic, copy   ) IBInspectable NSString *increaseTitle;
    /** 减按钮标题 */
    @property (nonatomic, copy   ) IBInspectable NSString *decreaseTitle;
    
    /** 最小值, default is 1 */
    @property (nonatomic, assign ) IBInspectable NSInteger minValue;
    /** 最大值 */
    @property (nonatomic, assign ) NSInteger maxValue;
    
    @end
    
    #pragma mark - NSString分类
    @interface NSString (PPNumberButton)
    /**
     字符串 nil, @"", @"  ", @"
    " Returns NO;
     其他 Returns YES.
     */
    - (BOOL)isNotBlank;
    @end
    .m
    
    #import "PPNumberButton.h"
    
    #ifdef DEBUG
    #define PPLog(...) printf("[%s] %s [第%d行]: %s
    ", __TIME__ ,__PRETTY_FUNCTION__ ,__LINE__, [[NSString stringWithFormat:__VA_ARGS__] UTF8String])
    #else
    #define PPLog(...)
    #endif
    
    
    @interface PPNumberButton () <UITextFieldDelegate>
    /** 减按钮*/
    @property (nonatomic, strong) UIButton *decreaseBtn;
    /** 加按钮*/
    @property (nonatomic, strong) UIButton *increaseBtn;
    /** 数量展示/输入框*/
    @property (nonatomic, strong) UITextField *textField;
    /** 快速加减定时器*/
    @property (nonatomic, strong) NSTimer *timer;
    /** 控件自身的宽*/
    @property (nonatomic, assign) CGFloat width;
    /** 控件自身的高*/
    @property (nonatomic, assign) CGFloat height;
    
    @end
    
    
    @implementation PPNumberButton
    
    #pragma mark - 初始化
    - (instancetype)initWithFrame:(CGRect)frame
    {
        if (self = [super initWithFrame:frame])
        {
            [self setupUI];
            //整个控件的默认尺寸(和某宝上面的按钮同样大小)
            if(CGRectIsEmpty(frame)) {self.frame = CGRectMake(0, 0, 110, 30);};
        }
        return self;
    }
    
    - (instancetype)initWithCoder:(NSCoder *)coder
    {
        if (self = [super initWithCoder:coder])
        {
            [self setupUI];
        }
        return self;
    }
    
    + (instancetype)numberButtonWithFrame:(CGRect)frame
    {
        return [[PPNumberButton alloc] initWithFrame:frame];
    }
    #pragma mark - 设置UI子控件
    - (void)setupUI
    {
        self.backgroundColor = [UIColor whiteColor];
        self.layer.cornerRadius = 3.f;
        self.clipsToBounds = YES;
        
        _minValue = 1;
        _maxValue = NSIntegerMax;
        _inputFieldFont = 15;
        _buttonTitleFont = 17;
        
        //加,减按钮
        _increaseBtn = [self creatButton];
        _decreaseBtn = [self creatButton];
        [self addSubview:_decreaseBtn];
        [self addSubview:_increaseBtn];
        
        //数量展示/输入框
        _textField = [[UITextField alloc] init];
        _textField.delegate = self;
        _textField.textAlignment = NSTextAlignmentCenter;
        _textField.keyboardType = UIKeyboardTypeNumberPad;
        _textField.font = [UIFont systemFontOfSize:_inputFieldFont];
        _textField.text = [NSString stringWithFormat:@"%ld",_minValue];
        
        [self addSubview:_textField];
    }
    
    //设置加减按钮的公共方法
    - (UIButton *)creatButton
    {
        UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
        button.titleLabel.font = [UIFont boldSystemFontOfSize:_buttonTitleFont];
        [button setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
        [button addTarget:self action:@selector(touchDown:) forControlEvents:UIControlEventTouchDown];
        [button addTarget:self action:@selector(touchUp:) forControlEvents:UIControlEventTouchUpOutside|UIControlEventTouchUpInside|UIControlEventTouchCancel];
        return button;
    }
    
    #pragma mark - layoutSubviews
    - (void)layoutSubviews
    {
        [super layoutSubviews];
        
        _width =  self.frame.size.width;
        _height = self.frame.size.height;
        _textField.frame = CGRectMake(_height, 0, _width - 2*_height, _height);
        _increaseBtn.frame = CGRectMake(_width - _height, 0, _height, _height);
        
        // 当按钮为"减号按钮隐藏模式(饿了么/百度外卖/美团外卖按钮样式)"
        if (_decreaseHide)
        {
            _textField.hidden = YES;
            _textField.text = [NSString stringWithFormat:@"%ld",_minValue-1];
            _decreaseBtn.alpha = 0;
            _decreaseBtn.frame = CGRectMake(_width-_height, 0, _height, _height);
            self.backgroundColor = [UIColor clearColor];
        }
        else
        {
            _decreaseBtn.frame = CGRectMake(0, 0, _height, _height);
        }
    }
    
    #pragma mark - UITextFieldDelegate
    - (void)textFieldDidEndEditing:(UITextField *)textField
    {
        NSString *minValueString = [NSString stringWithFormat:@"%ld",_minValue];
        NSString *maxValueString = [NSString stringWithFormat:@"%ld",_maxValue];
        
        [textField.text isNotBlank] == NO || textField.text.integerValue < _minValue ? _textField.text = minValueString : nil;
        textField.text.integerValue > _maxValue ? _textField.text = maxValueString : nil;
        _numberBlock ? _numberBlock(_textField.text) : nil;
        _delegate ? [_delegate pp_numberButton:self number:_textField.text] : nil;
    }
    
    #pragma mark - 加减按钮点击响应
    /**
     点击: 单击逐次加减,长按连续快速加减
     */
    - (void)touchDown:(UIButton *)sender
    {
        [_textField resignFirstResponder];
        
        if (sender == _increaseBtn)
        {
            _timer = [NSTimer scheduledTimerWithTimeInterval:0.1f target:self selector:@selector(increase) userInfo:nil repeats:YES];
        }
        else
        {
            _timer = [NSTimer scheduledTimerWithTimeInterval:0.1f target:self selector:@selector(decrease) userInfo:nil repeats:YES];
        }
        [_timer fire];
    }
    
    /**
     手指松开
     */
    - (void)touchUp:(UIButton *)sender
    {
        [self cleanTimer];
    }
    
    /**
     加运算
     */
    - (void)increase
    {
        [_textField.text isNotBlank] == NO ? _textField.text = [NSString stringWithFormat:@"%ld",_minValue] : nil;
        NSInteger number = [_textField.text integerValue] + 1;
        
        if (number <= _maxValue)
        {
            // 当按钮为"减号按钮隐藏模式",且输入框值==设定最小值,减号按钮展开
            if (_decreaseHide && number == _minValue)
            {
                [self rotationAnimationMethod];
                [UIView animateWithDuration:0.25 animations:^{
                    _decreaseBtn.alpha = 1;
                    _decreaseBtn.frame = CGRectMake(0, 0, _height, _height);
                } completion:^(BOOL finished) {
                    _textField.hidden = NO;
                }];
            }
            
            _textField.text = [NSString stringWithFormat:@"%ld", number];
            _numberBlock ? _numberBlock(_textField.text) : nil;
            _delegate ? [_delegate pp_numberButton:self number:_textField.text] : nil;
        }
        else
        {
            if (_shakeAnimation) { [self shakeAnimationMethod]; }
            PPLog(@"已超过最大数量%ld",_maxValue);
        }
    }
    
    /**
     减运算
     */
    - (void)decrease
    {
        [_textField.text isNotBlank] == NO ? _textField.text = [NSString stringWithFormat:@"%ld",_minValue] : nil;
        NSInteger number = [_textField.text integerValue] - 1;
        
        if (number >= _minValue)
        {
            _textField.text = [NSString stringWithFormat:@"%ld", number];
            _numberBlock ? _numberBlock(_textField.text) : nil;
            _delegate ? [_delegate pp_numberButton:self number:_textField.text] : nil;
        }
        else
        {
            // 当按钮为"减号按钮隐藏模式",且输入框值 < 设定最小值,减号按钮隐藏
            if (_decreaseHide && number < _minValue) {
                _textField.hidden = YES;
                [self rotationAnimationMethod];
                [UIView animateWithDuration:0.25 animations:^{
                    _decreaseBtn.alpha = 0;
                    _decreaseBtn.frame = CGRectMake(_width-_height, 0, _height, _height);
                } completion:^(BOOL finished) {
                    _textField.text = [NSString stringWithFormat:@"%ld",_minValue-1];
                }];
                return;
            }
            if (_shakeAnimation) { [self shakeAnimationMethod]; }
            PPLog(@"数量不能小于%ld",_minValue);
        }
    }
    
    /**
     清除定时器
     */
    - (void)cleanTimer
    {
        if (_timer.isValid)
        {
            [_timer invalidate];
            _timer = nil;
        }
    }
    
    #pragma mark - 加减按钮的属性设置
    - (void)setMinValue:(NSInteger)minValue
    {
        _minValue = minValue;
        _textField.text = [NSString stringWithFormat:@"%ld",minValue];
    }
    
    - (void)setBorderColor:(UIColor *)borderColor
    {
        _borderColor = borderColor;
        
        _decreaseBtn.layer.borderColor = [borderColor CGColor];
        _increaseBtn.layer.borderColor = [borderColor CGColor];
        self.layer.borderColor = [borderColor CGColor];
        
        _decreaseBtn.layer.borderWidth = 0.5;
        _increaseBtn.layer.borderWidth = 0.5;
        self.layer.borderWidth = 0.5;
    }
    
    - (void)setButtonTitleFont:(CGFloat)buttonTitleFont
    {
        _buttonTitleFont = buttonTitleFont;
        _increaseBtn.titleLabel.font = [UIFont boldSystemFontOfSize:buttonTitleFont];
        _decreaseBtn.titleLabel.font = [UIFont boldSystemFontOfSize:buttonTitleFont];
    }
    
    - (void)setIncreaseTitle:(NSString *)increaseTitle
    {
        _increaseTitle = increaseTitle;
        [_increaseBtn setTitle:increaseTitle forState:UIControlStateNormal];
    }
    
    - (void)setDecreaseTitle:(NSString *)decreaseTitle
    {
        _decreaseTitle = decreaseTitle;
        [_decreaseBtn setTitle:decreaseTitle forState:UIControlStateNormal];
    }
    
    - (void)setIncreaseImage:(UIImage *)increaseImage
    {
        _increaseImage = increaseImage;
        [_increaseBtn setBackgroundImage:increaseImage forState:UIControlStateNormal];
    }
    
    - (void)setDecreaseImage:(UIImage *)decreaseImage
    {
        _decreaseImage = decreaseImage;
        [_decreaseBtn setBackgroundImage:decreaseImage forState:UIControlStateNormal];
    }
    
    #pragma mark - 输入框中的内容设置
    - (NSString *)currentNumber
    {
        return _textField.text;
    }
    
    - (void)setCurrentNumber:(NSString *)currentNumber
    {
        _textField.text = currentNumber;
    }
    
    - (void)setInputFieldFont:(CGFloat)inputFieldFont
    {
        _inputFieldFont = inputFieldFont;
        _textField.font = [UIFont systemFontOfSize:inputFieldFont];
    }
    #pragma mark - 核心动画
    /**
     抖动动画
     */
    - (void)shakeAnimationMethod
    {
        CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position.x"];
        CGFloat positionX = self.layer.position.x;
        animation.values = @[@(positionX-10),@(positionX),@(positionX+10)];
        animation.repeatCount = 3;
        animation.duration = 0.07;
        animation.autoreverses = YES;
        [self.layer addAnimation:animation forKey:nil];
    }
    /**
     旋转动画
     */
    - (void)rotationAnimationMethod
    {
        CABasicAnimation *rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
        rotationAnimation.toValue = @(M_PI*2);
        rotationAnimation.duration = 0.25;
        rotationAnimation.fillMode = kCAFillModeForwards;
        rotationAnimation.removedOnCompletion = NO;
        [_decreaseBtn.layer addAnimation:rotationAnimation forKey:nil];
    }
    
    @end
    
    
    #pragma mark - NSString分类
    
    @implementation NSString (PPNumberButton)
    - (BOOL)isNotBlank
    {
        NSCharacterSet *blank = [NSCharacterSet whitespaceAndNewlineCharacterSet];
        for (NSInteger i = 0; i < self.length; ++i)
        {
            unichar c = [self characterAtIndex:i];
            if (![blank characterIsMember:c])
            {
                return YES;
            }
        }
        return NO;
    }
    
    @end

    在需要的地方创建按钮就行了.

     PPNumberButton *numberButton = [PPNumberButton numberButtonWithFrame:CGRectMake(100, 100, 110, 30)];
        // 开启抖动动画
        numberButton.shakeAnimation = YES;
        // 设置最小值
        numberButton.minValue = 1;
        // 设置最大值
        numberButton.maxValue = 10;
        // 设置输入框中的字体大小
        numberButton.inputFieldFont = 23;
        numberButton.increaseTitle = @"";
        numberButton.decreaseTitle = @"";
        
        numberButton.numberBlock = ^(NSString *num){
            NSLog(@"%@",num);
        };
        [self.view addSubview:numberButton];

    源码地址:

    GitHub: https://github.com/jkpang;

  • 相关阅读:
    只能输入数字的文本框
    Ajax
    Crtl+Enter提交留言
    onkeydown onkeyup键盘事件
    面向对象基础
    JS鼠标拖拽
    博客收藏
    不错的按钮
    如何在你的java程序中注册系统级热键
    开源GIS系统
  • 原文地址:https://www.cnblogs.com/LzwBlog/p/6390820.html
Copyright © 2020-2023  润新知