iOS系统提供的UISlider已经能满足很多需求,如果不行在继承于UISlider自定义稍微自定义一下,功能很全。包括添加点击事件,设置“播放点”等这些功能都可通过继承自定义实现。
以下是继承UISlider实现的半个自定义的点播slider
- 设置进度条高度
- slider添加progress
- slider点击
slider实现
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@class PlayerSlider;
@protocol PlayerSliderDelegate <NSObject>
- (void)sliderTouchBegan:(PlayerSlider *)slider;
- (void)sliderValueChanged:(PlayerSlider *)slider;
- (void)sliderTouchEnded:(PlayerSlider *)slider;
- (void)sliderSignleTouch:(PlayerSlider *)slider;
@end
@interface PlayerSlider : UISlider
@property (nonatomic, weak) id <PlayerSliderDelegate> delegate;
@property (nonatomic, assign) BOOL isDragging;
@property (nonatomic, strong) UIProgressView *progressView;
@end
NS_ASSUME_NONNULL_END
#import "PlayerSlider.h"
@interface PlayerSlider ()
@property (nonatomic, strong) UITapGestureRecognizer *sliderTap;
@end
@implementation PlayerSlider
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self addInitUI];
[self addSliderTarget];
[self sliderDefaultSet];
}
return self;
}
- (instancetype)init {
if (self = [super init]) {
[self addInitUI];
[self addSliderTarget];
[self sliderDefaultSet];
}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
//坐标x 预留出滑块的宽度
_progressView.frame = CGRectMake(20, CGRectGetHeight(self.frame)*0.5-1, CGRectGetWidth(self.frame)-20, 2);
}
//设置进度条高度为2
- (CGRect)trackRectForBounds:(CGRect)bounds
{
CGRect suBounds = [super trackRectForBounds:bounds];
return CGRectMake(suBounds.origin.x, suBounds.origin.y, suBounds.size.width, 2);
}
//设置滑块可触摸范围大小
- (CGRect)thumbRectForBounds:(CGRect)bounds trackRect:(CGRect)rect value:(float)value
{
CGRect suBounds = [super thumbRectForBounds:bounds trackRect:rect value:value];
return CGRectMake(suBounds.origin.x, suBounds.origin.y-10, suBounds.size.width+20, suBounds.size.height+20);
}
- (void)addInitUI {
_progressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
_progressView.progressTintColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:0.6];
_progressView.trackTintColor = [UIColor clearColor];
_progressView.layer.masksToBounds = YES;
_progressView.layer.cornerRadius = 1;
_progressView.progress = 0;
[self addSubview:_progressView];
[self sendSubviewToBack:_progressView];
}
- (void)addSliderTarget {
// slider开始滑动事件
[self addTarget:self action:@selector(progressSliderTouchBegan:) forControlEvents:UIControlEventTouchDown];
// slider滑动中事件
[self addTarget:self action:@selector(progressSliderValueChanged:) forControlEvents:UIControlEventValueChanged];
// slider结束滑动事件
[self addTarget:self action:@selector(progressSliderTouchEnded:) forControlEvents:UIControlEventTouchUpInside | UIControlEventTouchUpOutside];
// slider点击事件
self.sliderTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(sliderTapAction:)];
[self addGestureRecognizer:self.sliderTap];
}
- (void)sliderDefaultSet {
[self setMinimumTrackTintColor:[UIColor colorWithRed:0/255.0 green:122/255.0 blue:255/255.0 alpha:1.0]];
[self setMaximumTrackTintColor:[UIColor colorWithRed:255/255.0 green:255/255.0 blue:255/255.0 alpha:0.5]];
[self setThumbImage:[UIImage imageNamed:@"SKinBundle.bundle/seekbar"] forState:UIControlStateNormal];
}
- (void)progressSliderTouchBegan:(UISlider *)sender {
self.sliderTap.enabled = NO;
self.isDragging = YES;
if ([self.delegate respondsToSelector:@selector(sliderTouchBegan:)]) {
[self.delegate sliderTouchBegan:self];
}
}
- (void)progressSliderValueChanged:(UISlider *)sender {
if ([self.delegate respondsToSelector:@selector(sliderValueChanged:)]) {
[self.delegate sliderValueChanged:self];
}
}
- (void)progressSliderTouchEnded:(UISlider *)sender {
if ([self.delegate respondsToSelector:@selector(sliderTouchEnded:)]) {
[self.delegate sliderTouchEnded:self];
}
self.sliderTap.enabled = YES;
self.isDragging = NO;
}
- (void)sliderTapAction:(UITapGestureRecognizer *)tap
{
self.isDragging = YES;
CGPoint point = [tap locationInView:self];
CGFloat value = (self.maximumValue - self.minimumValue) * (point.x / self.frame.size.width );
[self setValue:value animated:YES];
if ([self.delegate respondsToSelector:@selector(sliderSignleTouch:)]) {
[self.delegate sliderSignleTouch:self];
}
self.isDragging = NO;
}
@end
+ (NSString *)timeFormat:(NSInteger)totalTime {
if (totalTime < 0) {
return @"00:00";
}
NSInteger durHour = totalTime / 3600;
NSInteger durMin = (totalTime / 60) % 60;
NSInteger durSec = totalTime % 60;
if (durHour > 0) {
return [NSString stringWithFormat:@"%zd:%02zd:%02zd", durHour, durMin, durSec];
} else {
return [NSString stringWithFormat:@"%02zd:%02zd", durMin, durSec];
}
}
slider设置
将点播播放器的时间设置到slider上,实现进度显示。
- (void)setProgressTime:(CGFloat)currentTime totalTime:(CGFloat)totalTime playableValue:(CGFloat)playable
{
if (!self.vodSlider.isDragging) {
//总时长
self.vodTotalTimeLabel.text = [PlayerSkinTool timeFormat:totalTime];
//更新当前播放时间
self.vodCurrentTimeLabel.text = [PlayerSkinTool timeFormat:currentTime];
// 更新slider
self.vodSlider.maximumValue = totalTime;
self.vodSlider.minimumValue = 0.0;
self.vodSlider.value = currentTime;
}
//更新缓存时长
[self.vodSlider.progressView setProgress:playable/totalTime animated:NO];
}
注意事项
滑块进度与点播播放器的事件要保持同步,滑动滑块,播放器seek,如果发现seek后滑块会往回“跳”的情况,大多数是没同步导致的。