结合了ProgressView的UISlider

时间:2010-12-21 00:54:51

标签: objective-c ios4 streaming uislider uiprogressview

是否有苹果屋制造的方式来获得带有ProgressView的UISlider。这由许多流应用程序使用,例如本机quicktimeplayer或youtube。 (只是为了确定:我只对可视化感兴趣)

Slider  with loader

欢呼西蒙

9 个答案:

答案 0 :(得分:47)

以下是您所描述内容的简单版本。

alt text

从某种意义上来说,它是“简单的”,我并不打算尝试添加阴影和其他细微之处。但它很容易构建,如果你愿意,你可以调整它以更微妙的方式绘制。例如,您可以制作自己的图像并将其用作滑块的拇指。

这实际上是一个位于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))
   
}