UISlider with ProgressView combined

Solution that suits my design:

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)
    }
} 


Here's a simple version of what you're describing.

alt text

It is "simple" in the sense that I didn't bother trying to add the shading and other subtleties. But it's easy to construct and you can tweak it to draw in a more subtle way if you like. For example, you could make your own image and use it as the slider's thumb.

This is actually a UISlider subclass lying on top of a UIView subclass (MyTherm) that draws the thermometer, plus two UILabels that draw the numbers.

The UISlider subclass eliminates the built-in track, so that the thermometer behind it shows through. But the UISlider's thumb (knob) is still draggable in the normal way, and you can set it to a custom image, get the Value Changed event when the user drags it, and so on. Here is the code for the UISlider subclass that eliminates its own track:

- (CGRect)trackRectForBounds:(CGRect)bounds {
    CGRect result = [super trackRectForBounds:bounds];
    result.size.height = 0;
    return result;
}

The thermometer is an instance of a custom UIView subclass, MyTherm. I instantiated it in the nib and unchecked its Opaque and gave it a background color of Clear Color. It has a value property so it knows how much to fill the thermometer. Here's its drawRect: code:

- (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));
}

To change the thermometer value, change the MyTherm instance's value to a number between 0 and 1, and tell it to redraw itself with setNeedsDisplay.


This is doable using the standard controls.

In Interface Builder place your UISlider immediately on top of your UIProgressView and make them the same size.

On a UISlider the background horizontal line is called the track, the trick is to make it invisible. We do this with a transparent PNG and the UISlider methods setMinimumTrackImage:forState: and setMaximumTrackImage:forState:.

In the viewDidLoad method of your view controller add:

[self.slider setMinimumTrackImage:[UIImage imageNamed:@"transparent.png"] forState:UIControlStateNormal];
[self.slider setMaximumTrackImage:[UIImage imageNamed:@"transparent.png"] forState:UIControlStateNormal];

where self.slider refers to your UISlider.

I've tested the code in Xcode, and this will give you a slider with an independent progress bar.


Create a 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);

   }

Enjoy! P.S. I might have some typos.