iOS 玩转UISlider

0.922字数 722阅读 7626
前言
  • UISlider控件的常规使用想必大家在日常iOS开发中用的肯定是非常熟练了,其使用场景也比较广泛,比如:音量大小字体大小背光亮度播放进度拍照缩放等等。最近,笔者在做自定义相机功能模块中,就用UISlider控件来做拍照缩放的功能,主要是自定义UISlider,都是利用大家不常用到的API来实现的,有兴趣的童鞋可以看看。
  • 本文将着重讲解UISlider的使用,希望大家在看完本篇文章后,能够对UISlider有新的认识,真正运用到实际项目开发中去,争取玩转UISlider。文章仅供大家参考,若有不妥之处,还望不吝赐教,欢迎批评指正。
效果图
UISlider效果图.gif
常规操作

平常开发中,我们可以利用UISlider提供的相关属性API可以实现大部分的需求,话不多说,这里笔者先讲讲各个属性API的使用。

  • Property & API
这个值是介于滑块的最大值和最小值之间的,如果没有设置边界值,默认为0-1;
@property(nonatomic) float value; 

设置滑块最小边界值(默认为0)
@property(nonatomic) float minimumValue;  

设置滑块最大边界值(默认为1)
@property(nonatomic) float maximumValue;

设置滑块最左端显示的图片:
@property(nonatomic,retain) UIImage *minimumValueImage;

设置滑块最右端显示的图片:
@property(nonatomic,retain) UIImage *maximumValueImage;

设置滑块值是否连续变化(默认为YES),这个属性设置为YES则在滑动时,其value就会随时变化,设置为NO,则当滑动结束时,value才会改变。
@property(nonatomic,getter=isContinuous) BOOL continuous; 

设置滑块左边(小于部分)线条的颜色
@property(nonatomic,retain) UIColor *minimumTrackTintColor;

设置滑块右边(大于部分)线条的颜色
@property(nonatomic,retain) UIColor *maximumTrackTintColor;

设置滑块颜色(影响已划过一端的颜色)
注意这个属性:如果你没有设置滑块的图片,那个这个属性将只会改变已划过一段线条的颜色,不会改变滑块的颜色,如果你设置了滑块的图片,又设置了这个属性,那么滑块的图片将不显示,滑块的颜色会改变(IOS7)
@property(nonatomic,retain) UIColor *thumbTintColor;

手动设置滑块的值:
- (void)setValue:(float)value animated:(BOOL)animated;

设置滑块的图片:
- (void)setThumbImage:(UIImage *)image forState:(UIControlState)state;

设置滑块划过部分的线条图案
- (void)setMinimumTrackImage:(UIImage *)image forState:(UIControlState)state;

设置滑块未划过部分的线条图案
- (void)setMaximumTrackImage:(UIImage *)image forState:(UIControlState)state;

对应的几个get方法
- (UIImage *)thumbImageForState:(UIControlState)state;
- (UIImage *)minimumTrackImageForState:(UIControlState)state;
- (UIImage *)maximumTrackImageForState:(UIControlState)state;

对应的设置当前状态的响应属性的方法
@property(nonatomic,readonly) UIImage* currentThumbImage;
@property(nonatomic,readonly) UIImage* currentMinimumTrackImage;
@property(nonatomic,readonly) UIImage* currentMaximumTrackImage;

添加触发事件
[slider addTarget:self action:@selector(log:) forControlEvents:UIControlEventValueChanged];

比较常用的属性以及作用如下图所示:


UISlider常用属性.png
  • Usage
#pragma mark - 常规操作
- (void)_generalOperations{
    
    /// 创建Slider 设置Frame
    UISlider *slider = [[UISlider alloc] initWithFrame:CGRectMake((MH_SCREEN_WIDTH - 247) * .5f, MH_SCREEN_HEIGHT*.5f- 50*.5f, 247, 50)];
    self.slider = slider;
    /// 添加Slider
    [self.view addSubview:slider];
    
    /// 属性配置
    // minimumValue  : 当值可以改变时,滑块可以滑动到最小位置的值,默认为0.0
    slider.minimumValue = 0.0;
    // maximumValue : 当值可以改变时,滑块可以滑动到最大位置的值,默认为1.0
    slider.maximumValue = 100.0;
    // 当前值,这个值是介于滑块的最大值和最小值之间的,如果没有设置边界值,默认为0-1;
    slider.value = 50;
    
    // continuous : 如果设置YES,在拖动滑块的任何时候,滑块的值都会改变。默认设置为YES
    [slider setContinuous:YES];
    
    UIImage * minimumValueImage = MHImageNamed(@"zoom-");
    UIImage * maximumValueImage = MHImageNamed(@"zoom+");
    // 滑块条最小值处设置的图片,默认为nil
    slider.minimumValueImage = minimumValueImage;
    // 滑块条最大值处设置的图片,默认为nil
    slider.maximumValueImage = maximumValueImage;
    
    // minimumTrackTintColor : 小于滑块当前值滑块条的颜色,默认为蓝色
    slider.minimumTrackTintColor = [UIColor redColor];
    // maximumTrackTintColor: 大于滑块当前值滑块条的颜色,默认为白色
    slider.maximumTrackTintColor = [UIColor blueColor];
    // thumbTintColor : 当前滑块的颜色,默认为白色
    slider.thumbTintColor = [UIColor yellowColor];
    
    // minimumTrackTintColor : 小于滑块当前值滑块条的颜色,默认为蓝色
    slider.minimumTrackTintColor = [UIColor redColor];
    // maximumTrackTintColor: 大于滑块当前值滑块条的颜色,默认为白色
    slider.maximumTrackTintColor = [UIColor blueColor];
    // thumbTintColor : 当前滑块的颜色,默认为白色
    slider.thumbTintColor = [UIColor yellowColor];
    
    /**  PS: 设置图片的优先级高于设置tintColor
     
    /// 设置滑块条最大值处设置的图片在不同的状态
    [slider setMaximumTrackImage:MHImageNamed(@"slider_bg") forState:UIControlStateNormal];
    /// 设置滑块条最小值处设置的图片在不同的状态
    [slider setMinimumTrackImage:MHImageNamed(@"slider_bg") forState:UIControlStateNormal];
    /// 设置滑块图片在不同的状态
    [slider setThumbImage:MHImageNamed(@"slider_thumb") forState:UIControlStateNormal];
    [slider setThumbImage:MHImageNamed(@"slider_thumb") forState:UIControlStateHighlighted];
     
     */
    
    /// currentMaximumTrackImage : 当前(状态)滑块条最大值处设置的图片
    /// currentMinimumTrackImage : 当前(状态)滑块条最小值处设置的图片
    /// currentThumbImage: 当前(状态)滑块的图片
    /// - (nullable UIImage *)thumbImageForState:(UIControlState)state; /// 获取某个(状态)滑块的图片
    /// - (nullable UIImage *)minimumTrackImageForState:(UIControlState)state; /// 获取某个(状态)滑块条最小值处设置的图片
    /// - (nullable UIImage *)maximumTrackImageForState:(UIControlState)state; /// 获取某个(状态)滑块条最大值处设置的图片
    
    /// 事件监听
    [slider addTarget:self action:@selector(_sliderValueDidChanged:) forControlEvents:UIControlEventValueChanged];

    /// label
    UILabel *lb = [UILabel mh_labelWithText:@"常规操作" fontSize:16 textColor:[UIColor whiteColor]];
    lb.textAlignment = NSTextAlignmentRight;
    [self.view addSubview:lb];
    CGFloat lbX = 0;
    CGFloat lbY = CGRectGetMinY(slider.frame);
    CGFloat lbW = CGRectGetMinX(slider.frame) - 20;
    CGFloat lbH = CGRectGetHeight(slider.frame);
    lb.frame = CGRectMake(lbX, lbY, lbW, lbH);
    
}

效果图如下:

UISlider常规使用.png
另类操作

常规操作想必大家都比较熟练,但是有些时候我们需要自定义UISlider内部的子控件的大小或位置等。首先我们先看看UISlider的子控件视图层级结构,如下所示:

UISlider层级结构.png

如果大家对其层级不了解的话,就会手忙脚乱,不知从何下手,以至于会直接弃用UISlider控件,自己重新自定义UIView来实现,很明显这就是对UISlider的使用不够熟练导致的,因为UISlider已经提供了相关的API,只要子类重写相关API来实现子控件的Rect

  • API
// 子类重写
/// 设置minimumValueImage的rect
- (CGRect)minimumValueImageRectForBounds:(CGRect)bounds;

/// 设置maximumValueImage的rect
- (CGRect)maximumValueImageRectForBounds:(CGRect)bounds;

/// 设置track(滑条)尺寸
- (CGRect)trackRectForBounds:(CGRect)bounds;

/// 设置thumb(滑块)尺寸
- (CGRect)thumbRectForBounds:(CGRect)bounds trackRect:(CGRect)rect value:(float)value;

关于这几个API的作用如下:

UISlider_API作用.png
  • Usage
#pragma mark - 另类操作
- (void)_alternativeOperation{
    
    MHCameraZoomSlider *slider = [[MHCameraZoomSlider alloc] init];
    slider.hidden = YES;
    [self.view addSubview:slider];
    /// 逆时针旋转90度
    slider.transform = CGAffineTransformMakeRotation(-M_PI_2);
    /// 事件监听
    [slider addTarget:self action:@selector(_sliderValueDidChanged:) forControlEvents:UIControlEventValueChanged];
    /// 设置Frame
    CGFloat sliderW = 247;
    CGFloat sliderH = 36;
    CGFloat sliderX = (self.view.mh_width - sliderH) *.5f;
    CGFloat sliderY = CGRectGetMaxY(self.slider.frame) + 100;
    slider.frame = CGRectMake(sliderX, sliderY, sliderH, sliderW);
    
    
    /// label
    UILabel *lb = [UILabel mh_labelWithText:@"另类操作" fontSize:16 textColor:[UIColor whiteColor]];
    lb.textAlignment = NSTextAlignmentRight;
    [self.view addSubview:lb];
    CGFloat lbX = 0;
    CGFloat lbY = 0;
    CGFloat lbW = CGRectGetMinX(self.slider.frame) - 20;
    CGFloat lbH = 40;
    lb.frame = CGRectMake(lbX, lbY, lbW, lbH);
    lb.mh_centerY = slider.mh_centerY;
}


MHCameraZoomSlider.m 内容如下:

#import "MHCameraZoomSlider.h"

@interface MHCameraZoomSlider ()

/// 是否设置过layer
@property (nonatomic , readwrite , assign) BOOL didSetLayer;

@end


@implementation MHCameraZoomSlider

- (instancetype)initWithFrame:(CGRect)frame{
    if (self = [super initWithFrame:frame]) {
        // 初始化
        [self _setup];
        
        // 创建自控制器
        [self _setupSubViews];
        
        // 布局子控件
        [self _makeSubViewsConstraints];
    }
    return self;
}

#pragma mark - 事件处理Or辅助方法

#pragma mark - Private Method
- (void)_setup{
    self.minimumValue = 1;
    self.maximumValue = 5;
}

#pragma mark - 创建自控制器
- (void)_setupSubViews
{
    self.minimumTrackTintColor = [[UIColor whiteColor] colorWithAlphaComponent:.4];
    self.maximumTrackTintColor = self.minimumTrackTintColor;
    
    UIImage * minimumValueImage = MHImageNamed(@"zoom-");
    self.minimumValueImage = [minimumValueImage imageByRotateRight90];
    UIImage * maximumValueImage = MHImageNamed(@"zoom+");
    self.maximumValueImage = [maximumValueImage imageByRotateRight90];
    
    UIImage *norImage = MHImageNamed(@"slider_dot");
    UIImage *highImage = MHImageNamed(@"slider_dot_pressed");
    /// 图片合成
    UIGraphicsBeginImageContextWithOptions(highImage.size , NO, highImage.scale);
    [highImage drawInRect:CGRectMake(0, 0, highImage.size.width, highImage.size.height)];
    CGFloat w = norImage.size.width;
    CGFloat h = norImage.size.height;
    CGFloat x = (highImage.size.width - w) * .5f;
    CGFloat y = (highImage.size.height - h) * .5f;
    [norImage drawInRect:CGRectMake(x, y, w, h) withContentMode:UIViewContentModeScaleAspectFit clipsToBounds:NO];
    highImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    [self setThumbImage:norImage forState:UIControlStateNormal];
    [self setThumbImage:highImage forState:UIControlStateHighlighted];
}

#pragma mark - 布局子控件
- (void)_makeSubViewsConstraints{
    
}



#pragma mark - Override
/// 设置minimumValueImage的rect
- (CGRect)minimumValueImageRectForBounds:(CGRect)bounds{
    CGFloat X = 0;
    CGFloat H = 21;
    CGFloat Y =( bounds.size.height - H ) *.5f;
    CGFloat W = H;
    return CGRectMake(X, Y, W, H);
    
}
/// 设置maximumValueImage的rect
- (CGRect)maximumValueImageRectForBounds:(CGRect)bounds{
    CGFloat H = 21;
    CGFloat Y =( bounds.size.height - H ) *.5f;
    CGFloat W = H;
    CGFloat X = bounds.size.width - W;
    return CGRectMake(X, Y, W, H);
}

/// 设置track(滑条)尺寸
- (CGRect)trackRectForBounds:(CGRect)bounds{
    CGRect minimumValueImageRect = [self minimumValueImageRectForBounds:bounds];
    CGRect maximumValueImageRect = [self maximumValueImageRectForBounds:bounds];
    CGFloat margin = 2;
    CGFloat H = 6;
    CGFloat Y =( bounds.size.height - H ) *.5f;
    CGFloat X = CGRectGetMaxX(minimumValueImageRect) + margin;
    CGFloat W = CGRectGetMinX(maximumValueImageRect) - X - margin;
    return CGRectMake(X, Y, W, H);
}

/// 设置thumb(滑块)尺寸
- (CGRect)thumbRectForBounds:(CGRect)bounds trackRect:(CGRect)rect value:(float)value{
    
    CGFloat WH = 30;
    CGFloat margin = WH *.5f - 21 *.5f + 2;
    /// 滑块的滑动区域宽度
    CGFloat maxWidth = CGRectGetWidth(rect) + 2 * margin;
    /// 每次偏移量
    CGFloat offset = (maxWidth - WH)/(self.maximumValue - self.minimumValue);
    
    CGFloat H = WH;
    CGFloat Y = (bounds.size.height - H ) *.5f;
    CGFloat W = H;
    CGFloat X = CGRectGetMinX(rect) - margin + offset *(value-self.minimumValue);
    CGRect r =  CGRectMake(X, Y, W, H);
    return r;
}


#pragma mark - 布局
- (void)layoutSubviews{
    [super layoutSubviews];
    
    if (self.didSetLayer) {
        return;
    }
    BOOL didSetLayer = NO;
    for (UIView *v in self.subviews) {
        if (v.mh_height <= 6 &&  self.mh_height > 0) {
            v.layer.borderWidth = 0.5f;
            v.layer.borderColor = MHColorFromHexString(@"#2C2E30").CGColor;
            v.layer.cornerRadius = MHConvertToFitPt(6) *.5f;
            v.layer.masksToBounds = YES;
            didSetLayer = YES;
        }
    }
    self.didSetLayer = didSetLayer;
}

@end

效果图如下:

UISlider另类使用.png

以上就是笔者实际项目中用于拍照放大缩小的小控件(MHCameraZoomSlider),相比于自定义UIView来实现的话,这种重写的方法是不是会更加简单、高效。其实平常开发中我们都可以在系统提供的控件基础上,去进行修改和调整,而不是一味地去自定义UIView。总之,多多熟练,百炼成钢。

期待
  • 文章若对您有些许帮助,请给个喜欢❤️,毕竟码字不易;若对您没啥帮助,请给点建议💗,切记学无止境。
  • 针对文章所述内容,阅读期间任何疑问;请在文章底部评论指出,我会火速解决和修正问题。
  • GitHub地址:https://github.com/CoderMikeHe

推荐阅读更多精彩内容