是否有苹果屋制造的方式来获得带有ProgressView的UISlider。这由许多流应用程序使用,例如本机quicktimeplayer或youtube。 (只是为了确定:我只对可视化感兴趣)
欢呼西蒙
答案 0 :(得分:47)
以下是您所描述内容的简单版本。
从某种意义上来说,它是“简单的”,我并不打算尝试添加阴影和其他细微之处。但它很容易构建,如果你愿意,你可以调整它以更微妙的方式绘制。例如,您可以制作自己的图像并将其用作滑块的拇指。
这实际上是一个位于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的一个实例。我在笔尖中实例化它并取消选中它的不透明并给它一个Clear Color的背景颜色。它具有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
重绘自己。
答案 1 :(得分:20)
使用标准控件可以做到这一点。
在界面生成器中,将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];
其中self.slider
指的是UISlider
。
我已经在Xcode中测试了代码,这将为您提供一个带有独立进度条的滑块。
答案 2 :(得分:4)
创建一个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);
}
享受!附:我可能会有一些错别字。
答案 3 :(得分:4)
适合我设计的解决方案:
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)
}
}
答案 4 :(得分:3)
创意1: 您可以通过子类化将UISlider轻松地用作进度视图。它响应诸如'setValue:animated:'之类的方法,您可以使用它来设置视图的值(即:progress)。
您在示例中创建的唯一“限制”是缓冲栏,您可以通过“创造性地”为UISlider设置外观(因为您可以向其添加自定义外观)来创建,也可以通过编程方式设置该外观。 / p>
创意2: 另一个(更简单)选项是子类UIProgressView,并在该子类中创建一个UISlider。您可以将UISlider设置为透视皮肤(没有条形,只有旋钮可见)并将其放在UIProgressView上。
您可以使用UIProgressView进行预加载(缓冲),使用UISlider进行电影控制/进度指示。
似乎相当容易: - )
编辑实际回答您的问题,没有内部方式,但使用所提供的工具很容易实现。
答案 5 :(得分:1)
你可以做这样的伎俩,更容易理解。只需在下面的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;
}
}
答案 6 :(得分:0)
添加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。
我花了太多时间寻找解决这个问题的方法,希望能节省一些时间给另一个可怜的灵魂;)。
答案 7 :(得分:0)
Here is a solution in 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
答案 8 :(得分:0)
对于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))
}