有没有一种苹果自制的方法来获取带有 ProgressView 的 UISlider。这被许多流媒体应用程序使用,例如本机 quicktimeplayer 或 youtube。(只是为了确定:我只对可视化感兴趣)
欢呼西蒙
有没有一种苹果自制的方法来获取带有 ProgressView 的 UISlider。这被许多流媒体应用程序使用,例如本机 quicktimeplayer 或 youtube。(只是为了确定:我只对可视化感兴趣)
欢呼西蒙
这是您所描述内容的简单版本。
从某种意义上说,它是“简单的”,因为我没有费心尝试添加阴影和其他细微之处。但它很容易构建,如果你愿意,你可以调整它以更微妙的方式绘制。例如,您可以制作自己的图像并将其用作滑块的拇指。
这实际上是一个位于绘制温度计的 UIView 子类 (MyTherm) 之上的 UISlider 子类,以及绘制数字的两个 UILabel。
UISlider 子类消除了内置轨道,以便它后面的温度计显示出来。但是 UISlider 的拇指(旋钮)仍然可以以正常方式拖动,并且可以将其设置为自定义图像,在用户拖动时获取 Value Changed 事件,等等。下面是消除自身轨迹的 UISlider 子类的代码:
- (CGRect)trackRectForBounds:(CGRect)bounds {
CGRect result = [super trackRectForBounds:bounds];
result.size.height = 0;
return result;
}
温度计是自定义 UIView 子类 MyTherm 的一个实例。我在笔尖中实例化它并取消选中它的不透明并给它一个透明颜色的背景颜色。它有一个value
属性,所以它知道温度计要装多少。这是它的drawRect:
代码:
- (void)drawRect:(CGRect)rect {
CGContextRef c = UIGraphicsGetCurrentContext();
[[UIColor whiteColor] set];
CGFloat ins = 2.0;
CGRect r = CGRectInset(self.bounds, ins, ins);
CGFloat radius = r.size.height / 2.0;
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, NULL, CGRectGetMaxX(r) - radius, ins);
CGPathAddArc(path, NULL, radius+ins, radius+ins, radius, -M_PI/2.0, M_PI/2.0, true);
CGPathAddArc(path, NULL, CGRectGetMaxX(r) - radius, radius+ins, radius, M_PI/2.0, -M_PI/2.0, true);
CGPathCloseSubpath(path);
CGContextAddPath(c, path);
CGContextSetLineWidth(c, 2);
CGContextStrokePath(c);
CGContextAddPath(c, path);
CGContextClip(c);
CGContextFillRect(c, CGRectMake(r.origin.x, r.origin.y, r.size.width * self.value, r.size.height));
}
要更改温度计值,请将 MyTherm 实例更改为value
0 到 1 之间的数字,并告诉它使用 重绘自身setNeedsDisplay
。
使用标准控件可以做到这一点。
在 Interface Builder 中,将您UISlider
立即放在您的顶部UIProgressView
并使其大小相同。
背景上UISlider
的水平线称为轨道,诀窍是使其不可见。我们使用透明 PNG 和UISlider
方法setMinimumTrackImage:forState:
和setMaximumTrackImage:forState:
.
在viewDidLoad
视图控制器的方法中添加:
[self.slider setMinimumTrackImage:[UIImage imageNamed:@"transparent.png"] forState:UIControlStateNormal];
[self.slider setMaximumTrackImage:[UIImage imageNamed:@"transparent.png"] forState:UIControlStateNormal];
whereself.slider
指的是你的UISlider
.
我已经在 Xcode 中测试了代码,这将为您提供一个带有独立进度条的滑块。
适合我的设计的解决方案:
class SliderBuffering:UISlider {
let bufferProgress = UIProgressView(progressViewStyle: .Default)
override init (frame : CGRect) {
super.init(frame : frame)
}
convenience init () {
self.init(frame:CGRect.zero)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
func setup() {
self.minimumTrackTintColor = UIColor.clearColor()
self.maximumTrackTintColor = UIColor.clearColor()
bufferProgress.backgroundColor = UIColor.clearColor()
bufferProgress.userInteractionEnabled = false
bufferProgress.progress = 0.0
bufferProgress.progressTintColor = UIColor.lightGrayColor().colorWithAlphaComponent(0.5)
bufferProgress.trackTintColor = UIColor.blackColor().colorWithAlphaComponent(0.5)
self.addSubview(bufferProgress)
}
}
创建一个 UISlider:
// 1
// Make the slider as a public propriety so you can access it
playerSlider = [[UISlider alloc] init];
[playerSlider setContinuous:YES];
[playerSlider setHighlighted:YES];
// remove the slider filling default blue color
[playerSlider setMaximumTrackTintColor:[UIColor clearColor]];
[playerSlider setMinimumTrackTintColor:[UIColor clearColor]];
// Chose your frame
playerSlider.frame = CGRectMake(--- , -- , yourSliderWith , ----);
// 2
// create a UIView that u can access and make it the shadow of your slider
shadowSlider = [[UIView alloc] init];
shadowSlider.backgroundColor = [UIColor lightTextColor];
shadowSlider.frame = CGRectMake(playerSlider.frame.origin.x , playerSlider.frame.origin.y , playerSlider.frame.size.width , playerSlider.frame.origin.size.height);
shadowSlider.layer.cornerRadius = 4;
shadowSlider.layer.masksToBounds = YES;
[playerSlider addSubview:shadowSlider];
[playerSlider sendSubviewToBack:shadowSlider];
// 3
// Add a timer Update your slider and shadow slider programatically
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(updateSlider) userInfo:nil repeats:YES];
-(void)updateSlider {
// Update the slider about the music time
playerSlider.value = audioPlayer.currentTime; // based on ur case
playerSlider.maximumValue = audioPlayer.duration;
float smartWidth = 0.0;
smartWidth = (yourSliderFullWidth * audioPlayer.duration ) / 100;
shadowSlider.frame = CGRectMake( shadowSlider.frame.origin.x , shadowSlider.frame.origin.y , smartWidth , shadowSlider.frame.size.height);
}
享受!PS我可能有一些错别字。
想法 1: 您可以通过继承 UISlider 轻松地将其用作进度视图。它响应诸如“setValue:animated:”之类的方法,您可以使用这些方法设置视图的值(即:进度)。
创建您在示例中看到的内容的唯一“限制”是缓冲区栏,您可以通过“创造性地”为 UISlider 蒙皮来创建它(因为您可以向其添加自定义皮肤),并且可能以编程方式设置该皮肤。
想法2: 另一个(更简单)的选择是继承UIProgressView,并在该子类中创建一个UISlider。您可以为 UISlider 设置透明皮肤(没有条,只有旋钮可见)并将其放置在 UIProgressView 上。
您可以使用 UIProgressView 进行预加载(缓冲),使用 UISlider 进行电影控制/进度指示。
看起来相当容易:-)
编辑:要真正回答您的问题,没有内部方法,但使用给定的工具很容易完成。
你可以做一些这样的技巧,它更容易理解。只需在您的 UISlider 子类中插入下面的代码。
- (void)layoutSubviews
{
[super layoutSubviews];
if (_availableDurationImageView == nil) {
// step 1
// get max length that our "availableDurationImageView" will show
UIView *maxTrackView = [self.subviews objectAtIndex:self.subviews.count - 3];
UIImageView *maxTrackImageView = [maxTrackView.subviews objectAtIndex:0];
_maxLength = maxTrackImageView.width;
// step 2
// get the right frame where our "availableDurationImageView" will place in superView
UIView *minTrackView = [self.subviews objectAtIndex:self.subviews.count - 2];
_availableDurationImageView = [[UIImageView alloc] initWithImage:[[UIImage imageNamed:@"MediaSlider.bundle/4_jindu_huancun.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 2, 0, 2)]];
_availableDurationImageView.opaque = NO;
_availableDurationImageView.frame = minTrackView.frame;
[self insertSubview:_availableDurationImageView belowSubview:minTrackView];
}
}
- (void)setAvailableValue:(NSTimeInterval)availableValue
{
if (availableValue >=0 && availableValue <= 1) {
// use "maxLength" and percentage to set our "availableDurationImageView" 's length
_availableDurationImageView.width = _maxLength * availableValue;
}
}
添加 matt 的解决方案,请注意,从 iOS 7.0 开始,实现 trackRectForBounds: 是不可能的。这是我对这个问题的解决方案:
在您的 UISlider 子类中,执行以下操作:
-(void)awakeFromNib
{
[super awakeFromNib];
UIImage* clearColorImage = [UIImage imageWithColor:[UIColor clearColor]];
[self setMinimumTrackImage:clearColorImage forState:UIControlStateNormal];
[self setMaximumTrackImage:clearColorImage forState:UIControlStateNormal];
}
用 imageWithColor 作为这个函数:
+ (UIImage*) imageWithColor:(UIColor*)color
{
return [UIImage imageWithColor:color andSize:CGSizeMake(1.0f, 1.0f)];
}
这将妥善处理这个烦人的 trackRectangle。
我花了太多时间寻找这个问题的解决方案,希望这能为另一个可怜的灵魂节省一些时间;)。
这是Objective C中的一个解决方案。 https://github.com/abhimuralidharan/BufferSlider
这个想法是在 UISlider 子类中创建一个 UIProgressview 作为属性,并以编程方式添加所需的约束。
#import <UIKit/UIKit.h> //.h file
@interface BufferSlider : UISlider
@property(strong,nonatomic) UIProgressView *bufferProgress;
@end
#import "BufferSlider.h" //.m file
@implementation BufferSlider
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setup];
}
return self;
}
-(void)setup {
self.bufferProgress = [[UIProgressView alloc] initWithFrame:self.bounds];
self.minimumTrackTintColor = [UIColor redColor];
self.maximumTrackTintColor = [UIColor clearColor];
self.value = 0.2;
self.bufferProgress.backgroundColor = [UIColor clearColor];
self.bufferProgress.userInteractionEnabled = NO;
self.bufferProgress.progress = 0.7;
self.bufferProgress.progressTintColor = [[UIColor blueColor] colorWithAlphaComponent:0.5];
self.bufferProgress.trackTintColor = [[UIColor lightGrayColor] colorWithAlphaComponent:2];
[self addSubview:self.bufferProgress];
[self setThumbImage:[UIImage imageNamed:@"redThumb"] forState:UIControlStateNormal];
self.bufferProgress.translatesAutoresizingMaskIntoConstraints = NO;
NSLayoutConstraint *left = [NSLayoutConstraint constraintWithItem:self.bufferProgress attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1 constant:0];
NSLayoutConstraint *centerY = [NSLayoutConstraint constraintWithItem:self.bufferProgress attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1 constant:0.75]; // edit the constant value based on the thumb image
NSLayoutConstraint *right = [NSLayoutConstraint constraintWithItem:self.bufferProgress attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTrailing multiplier:1 constant:0];
[self addConstraints:@[left,right,centerY]];
[self sendSubviewToBack:self.bufferProgress];
}
- (instancetype)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (self) {
[self setup];
}
return self;
}
@end
对于 Swift5
首先,将轻击手势添加到滑块:
let tap_gesture = UITapGestureRecognizer(target: self, action: #selector(self.sliderTapped(gestureRecognizer:)))
self.slider.addGestureRecognizer(tap_gesture)
然后,实现这个功能:
@objc func sliderTapped(gestureRecognizer: UIGestureRecognizer) {
let locationOnSlider = gestureRecognizer.location(in: self.slider)
let maxWidth = self.slider.frame.size.width
let touchLocationRatio = locationOnSlider.x * CGFloat(self.slider.maximumValue) / CGFloat(maxWidth)
self.slider.value = Float(touchLocationRatio)
print("New value: ", round(self.slider.value))
}