Wicked iOS Range Slider Part One

iOS gives developers a standard slider control, which is great when you only need a single value.
But what happens when you want the user to select a range – for example, a minimum and maximum price, distance, or time?

There’s no built-in range slider in UIKit.

You could try adding two sliders side by side, but that becomes messy, confusing, and wastes screen space.

The most practical solution is to build your own custom range slider, and in this two-part beginner series, you’ll learn exactly how to do that.

By the end of this first part Wicked iOS Range Slider Part One, you’ll have a working slider with movable “thumbs” and custom graphics.

What We’ll Cover in Part 1

  • Creating a new project for the slider
  • Importing graphics
  • Making a custom UIControl subclass
  • Adding slider tracks and draggable thumbs
  • Mapping slider values to on-screen positions
  • Handling touch interactions

Why Apple Doesn’t Include a Range Slider

Apple doesn’t provide a dedicated range slider control in UIKit.
However, range sliders do appear inside Apple apps — for example, when trimming a video in iPhoto or Photos, you’re actually using a form of range slider.

This proves one important thing:

Even though iOS doesn’t ship one by default, Apple clearly expects developers to build custom controls when needed.

And since fingers, not a mouse cursor, are involved – sizing, spacing, and usability become extremely important.

Developers building custom iOS UI components may also enjoy our advanced tutorial Creating a Graph with Quartz 2D (Part 2).

We’ll make sure our range slider respects those guidelines.

Step 1: Setting Up the Project

Start by creating a fresh Navigation-based iOS project (or use an existing project if you prefer).

You’ll need four images:

  • Slider track background
  • Highlighted (active) slider track
  • Thumb image
  • Highlighted thumb image

Remember to include both 1x and 2x resolutions so it looks good on retina and older screens.

Once you’ve got them:

  1. Drag the image folder into Xcode.
  2. When the dialog appears, check Copy items if needed.

Your assets are now ready to use.

Step 2: Creating a Custom Slider Class

The best way to build reusable UI components in iOS is by subclassing UIControl.

  1. Press Cmd+N → choose Objective-C Class
  2. Subclass from: UIControl
  3. Name it: RangeSlider

Inside RangeSlider.h, define the values your slider will represent:

@interface RangeSlider : UIControl {
float minimumValue;
float maximumValue;
float minimumRange;

float selectedMinimumValue;
float selectedMaximumValue;

}

@property(nonatomic) float minimumValue;
@property(nonatomic) float maximumValue;
@property(nonatomic) float minimumRange;
@property(nonatomic) float selectedMinimumValue;
@property(nonatomic) float selectedMaximumValue;

@end

Internal Variables

The slider needs a few internal helpers:

BOOL _minThumbOn;
BOOL _maxThumbOn;

float _padding;

UIImageView *_minThumb;
UIImageView *_maxThumb;
UIImageView *_track;
UIImageView *_trackBackground;

These handle:

  • Which thumb is currently being moved
  • Spacing from edges
  • The images for the two thumbs and the track

Adding the Slider to a Table Cell

RangeSlider *slider = [RangeSlider alloc];
slider.minimumValue = 1;
slider.selectedMinimumValue = 2;
slider.maximumValue = 10;
slider.selectedMaximumValue = 8;
slider.minimumRange = 2;

[slider initWithFrame:cell.bounds];
[cell addSubview:slider];

Step 3: Adding Tracks and Thumbs

Inside initWithFrame

1. Set defaults

_minThumbOn = false;
_maxThumbOn = false;
_padding = 20;

2. Add track background

_trackBackground = [[[UIImageView alloc]
initWithImage:[UIImage imageNamed:@"bar-background.png"]]
autorelease];

_trackBackground.frame = CGRectMake(
(frame.size.width - _trackBackground.frame.size.width) / 2,
(frame.size.height - _trackBackground.frame.size.height) / 2,
_trackBackground.frame.size.width,
_trackBackground.frame.size.height
);

[self addSubview:_trackBackground];

3. Add highlighted track

_track = [[[UIImageView alloc]
initWithImage:[UIImage imageNamed:@”bar-highlight.png”]]
autorelease];

_track.frame = CGRectMake(
(frame.size.width – _track.frame.size.width) / 2,
(frame.size.height – _track.frame.size.height) / 2,
_track.frame.size.width,
_track.frame.size.height
);

[self addSubview:_track];

4. Add thumb images

_minThumb = [[[UIImageView alloc]
initWithImage:[UIImage imageNamed:@"handle.png"]
highlightedImage:[UIImage imageNamed:@"handle-hover.png"]]
autorelease];

_minThumb.center = CGPointMake([self xForValue:selectedMinimumValue],
self.frame.size.height / 2);
[self addSubview:_minThumb];

_maxThumb = [[[UIImageView alloc]
initWithImage:[UIImage imageNamed:@"handle.png"]
highlightedImage:[UIImage imageNamed:@"handle-hover.png"]]
autorelease];

_maxThumb.center = CGPointMake([self xForValue:selectedMaximumValue],
self.frame.size.height / 2);
[self addSubview:_maxThumb];

Step 4: Converting Values into Positions

@interface RangeSlider (PrivateMethods)
-(float)xForValue:(float)value;
@end

The math (beginner-friendly):

  1. The slider track spans the width of your control minus padding.
  2. You calculate what percentage the current value is between min and max.
  3. You multiply that percentage by the track width.
  4. You offset by padding to position it inside the slider.

Here’s the full method:

-(float)xForValue:(float)value {
return (self.frame.size.width – (_padding * 2)) *
((value – minimumValue) / (maximumValue – minimumValue)) +
_padding;
}

Step 5: Making the Thumbs Movable

1. When the touch begins

-(BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
CGPoint point = [touch locationInView:self];

if (CGRectContainsPoint(_minThumb.frame, point)) {
_minThumbOn = true;
} else if (CGRectContainsPoint(_maxThumb.frame, point)) {
_maxThumbOn = true;
}

return YES;
}

2. When the touch ends

-(void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
_minThumbOn = false;
_maxThumbOn = false;
}

3. While the finger moves

-(BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {

if (!_minThumbOn && !_maxThumbOn)
    return YES;

CGPoint point = [touch locationInView:self];

if (_minThumbOn) {
    _minThumb.center =
    CGPointMake(MAX([self xForValue:minimumValue],
                    MIN(point.x,
                        [self xForValue:selectedMaximumValue - minimumRange])),
                _minThumb.center.y);
}

if (_maxThumbOn) {
    _maxThumb.center =
    CGPointMake(MIN([self xForValue:maximumValue],
                    MAX(point.x,
                        [self xForValue:selectedMinimumValue + minimumRange])),
                _maxThumb.center.y);
}

[self setNeedsDisplay];
return YES;

}

This ensures:

  • Thumbs cannot overlap
  • Thumbs cannot go beyond min/max
  • Minimum range is always respected

At this point, you have a fully interactive custom range slider:
✔ Custom images
✔ Two draggable thumbs
✔ Min/max limits
✔ Proper spacing and user interaction