前言
-
UISlider
控件的常规使用想必大家在日常iOS开发中用的肯定是非常熟练了,其使用场景也比较广泛,比如:音量大小
,字体大小
,背光亮度
,播放进度
,拍照缩放
等等。最近,笔者在做自定义相机功能模块中,就用UISlider
控件来做拍照缩放
的功能,主要是自定义UISlider
,都是利用大家不常用到的API来实现的,有兴趣的童鞋可以看看。 - 本文将着重讲解
UISlider
的使用,希望大家在看完本篇文章后,能够对UISlider
有新的认识,真正运用到实际项目开发中去,争取玩转UISlider
。文章仅供大家参考,若有不妥之处,还望不吝赐教,欢迎批评指正。
效果图
常规操作
平常开发中,我们可以利用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];
比较常用的属性以及作用如下图所示:
- 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
内部的子控件的大小或位置等。首先我们先看看UISlider
的子控件视图层级结构,如下所示:
如果大家对其层级不了解的话,就会手忙脚乱,不知从何下手,以至于会直接弃用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的作用如下:
- 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
效果图如下:
以上就是笔者实际项目中用于拍照放大缩小的小控件(MHCameraZoomSlider
),相比于自定义UIView
来实现的话,这种重写的方法是不是会更加简单、高效。其实平常开发中我们都可以在系统提供的控件基础上,去进行修改和调整,而不是一味地去自定义UIView
。总之,多多熟练,百炼成钢。
期待
- 文章若对您有些许帮助,请给个喜欢❤️,毕竟码字不易;若对您没啥帮助,请给点建议,切记学无止境。
- 针对文章所述内容,阅读期间任何疑问;请在文章底部评论指出,我会火速解决和修正问题。
- GitHub地址:https://github.com/CoderMikeHe