31

I'm using a UISlider in my app but I'd like to use a custom "look-and-feel" for it. I have changed the thumb to my own image but is there a way to change the bar also? I have a bar image I would like to use but can't see how to do this.

I have found how to change the max and min image but not the bar itself.

Alex Cio
  • 6,014
  • 5
  • 44
  • 74
Fogmeister
  • 76,236
  • 42
  • 207
  • 306
  • I have tried the [slider setMinimumTrackImage:forState:] method but this uses the image and scales it according to where the slider is placed. What I would like is to use a single image across the whole slider that remains static while the thumb is moved across it. Imagine a volume slider with a wedge to represent the relative volumes empty at one end and full at the other. When the slider is moved the wedge remains as it is. This is what I'd like to be able to do. Thanks! – Fogmeister Mar 04 '10 at 12:58
  • 2
    Can you share samples of the custom slider pictures with the users? – Ahsan Jun 04 '11 at 12:12

7 Answers7

60

You were right to use -setMinimumTrackImage:forState: and -setMaximumTrackImage:forState: methods. What you missed is that you should provide stretchable UIImage to them, the rest is taken care of automagically:

UIImage *sliderLeftTrackImage = [[UIImage imageNamed: @"SliderMin.png"] stretchableImageWithLeftCapWidth: 9 topCapHeight: 0];
UIImage *sliderRightTrackImage = [[UIImage imageNamed: @"SliderMax.png"] stretchableImageWithLeftCapWidth: 9 topCapHeight: 0];
[mySlider setMinimumTrackImage: sliderLeftTrackImage forState: UIControlStateNormal];
[mySlider setMaximumTrackImage: sliderRightTrackImage forState: UIControlStateNormal];

You can use the same image for both the min and max parts.

sunkehappy
  • 8,970
  • 5
  • 44
  • 65
Costique
  • 23,712
  • 4
  • 76
  • 79
25

The simplest solution would be to render a UIImage behind the control to represent the track. The thumbknob can be changed with:

[mySlider setThumbImage:[UIImage imageNamed:@"thumb_image.png"] forState:UIControlStateNormal];

A side-effect of this is that the track isn't rendered unless you provide your own. This, combined with the UIImage, provide you with a custom UISlider without you having to subclass anything.

Stephen Melvin
  • 3,696
  • 2
  • 27
  • 40
  • 3
    Doesn't appear to be true anymore for standard UISliders in iOS 5, unless I've missed something. – Tim Jan 13 '12 at 21:53
  • 4
    `[[UISlider appearanceWhenContainedIn:[self class], nil] setThumbImage:[UIImage...] forState:UIControlStateNormal];`. I think you can also do `UIControlStateHighlighted` to do a "touch down" image. – Hari Honor Aug 06 '12 at 11:00
8

Putting it all together in a modern way

If you define the UISlider in a Storyboard the best place to style the Slider is in the View's subclass. In awakeFromNib you can change the button, left and right track.

This call is deprecated in iOS 5 stretchableImageWithLeftCapWidth:topCapHeight:

- (void)awakeFromNib
{
    [super awakeFromNib];

    UIImage *thumbImage = [UIImage imageNamed:@"slider-button"];
    [self.slider setThumbImage:thumbImage forState:UIControlStateNormal];

    UIImage *sliderLeftTrackImage = [UIImage imageNamed: @"slider-fill"];
    sliderLeftTrackImage = [sliderLeftTrackImage resizableImageWithCapInsets:UIEdgeInsetsZero resizingMode:UIImageResizingModeStretch];
    UIImage *sliderRightTrackImage = [UIImage imageNamed: @"slider-track"];
    sliderRightTrackImage = [sliderRightTrackImage resizableImageWithCapInsets:UIEdgeInsetsZero resizingMode:UIImageResizingModeStretch];
    [self.slider setMinimumTrackImage:sliderLeftTrackImage forState:UIControlStateNormal];
    [self.slider setMaximumTrackImage:sliderRightTrackImage forState:UIControlStateNormal];
}
Cameron Lowell Palmer
  • 21,528
  • 7
  • 125
  • 126
8

enter image description here

Here is a way to add a track image that is not stretched so you can have e.g. a wedge shape in the background just as the OP asked:

Swift 3.0:

let trackImg = image.resizableImage(withCapInsets: .zero, resizingMode: .tile)
slider.setMinimumTrackImage(trackImg, for: .normal)
slider.setMaximumTrackImage(trackImg, for: .normal)

Important: make sure that the width of your slider is exactly the same as the width of the image!

Dorian Roy
  • 3,094
  • 2
  • 31
  • 51
4

stretchableImageWithLeftCapWidth: has been deprecated since iOS 5.0. The docs say to use 'capInsets' property instead. Here's an easy way to do that:

Create three images, the min (left) track, the max (right) track, and the thumb. For this example, assume the min and max track images are 34p H x 18p W, something like this: min track and this: enter image description here.

Create the images as usual:

UIImage *thumbImage = [UIImage imageNamed:@"sliderThumb.png"];

UIImage *sliderMinTrackImage = [UIImage imageNamed: @"sliderMin.png"];

UIImage *sliderMaxTrackImage = [UIImage imageNamed: @"sliderMax.png"];

For my 18 point wide image examples, the inner point on the left and the right can be stretched to fit the track, but the ends should have unstretchable cap sizes 17 points wide (hence the capInsets):

sliderMinTrackImage = [sliderMinTrackImage resizableImageWithCapInsets:UIEdgeInsetsMake(0, 17, 0, 0)];

sliderMaxTrackImage = [sliderMaxTrackImage resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 17)];

Then set the images on your UISlider as always:

[slider setThumbImage:thumbImage forState:UIControlStateNormal];
[slider setMinimumTrackImage:sliderMinTrackImage forState:UIControlStateNormal];
[slider setMaximumTrackImage:sliderMaxTrackImage forState:UIControlStateNormal];
Scotty
  • 540
  • 4
  • 7
1

You need to subclass UISlider and override:

- (CGRect)trackRectForBounds:(CGRect)bounds

Discussion You should not call this method directly. If you want to customize the track rectangle, you can override this method and return a different rectangle. The returned rectangle is used to scale the track and thumb images during drawing.

willcodejavaforfood
  • 43,223
  • 17
  • 81
  • 111
0

I am doing this but the back bar is not showing perfectly in iOS 5.1 but in iOS 6.0 its displaying

here is my code

 UIImage *stetchLeftTrack = [[UIImage imageNamed:@"spectrum_horizontal_bar.png"]
                                stretchableImageWithLeftCapWidth:15.0 topCapHeight:0.0];
 UIImage *stetchRightTrack = [[UIImage imageNamed:@"spectrum_horizontal_bar.png"]
                                 stretchableImageWithLeftCapWidth:15.0 topCapHeight:0.0];
 [self.slider_Sprectrum setMinimumTrackImage:stetchLeftTrack forState:UIControlStateNormal];
 [self.slider_Sprectrum setMaximumTrackImage:stetchRightTrack forState:UIControlStateNormal];
Bhavin Bhadani
  • 22,224
  • 10
  • 78
  • 108
Dk Kumar
  • 103
  • 1
  • 11
  • @Hari Karam Singh [[UISlider appearanceWhenContainedIn:[self class], nil] setMinimumTrackImage:stetchLeftTrack forState:UIControlStateNormal]; [[UISlider appearanceWhenContainedIn:[self class], nil] setMaximumTrackImage:stetchRightTrack forState:UIControlStateNormal]; – Dk Kumar Dec 24 '12 at 09:02
  • Hi Dk Kumar i am too facing same prob in IOS 5 but working in IOS 6.I am using two images for min and Max where both are same.Thumb image is a small transparent glow image.In IOS i could see a line behind the thumb...Can u plz help how you have solved in your case to avoid skewing/stretching... – Dinakar Feb 12 '13 at 15:05
  • try removing stretchableImageWithLeftCapWidth ... use only [UIImage imageNamed:@"spectrum_horizontal_bar.png"] ... It will start showing the correct colors while sliding the slider. Only one problem I noticed here that it changes the left corner radius of slider when you move to max and min value... I'm looking to its solutions too. – Ans Feb 17 '13 at 08:31
  • moreover, stretchableImageWithLeftCapWidth has deprecated in iOS 5. use resizableImageWithCapInsets as alternate. – Ans Feb 17 '13 at 08:34