23

I am creating a custom UISlider and wonder, how do you increase a thumb image's "click area" ? The code below works great, except the thumb's "click area" remains unchanged. If I am not wrong, I believe the standard thumb area is 19 px ? Lets say I would like to increase it to 35px with the following code below, what steps do I need to take? Keep in mind I am not an expert within this area at all.

EDIT The code below is corrected and ready for copy pasta! Hope it helps you!

main.h

#import "MyUISlider.h"

@interface main : MLUIViewController <UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate, UIActionSheetDelegate, UIAlertViewDelegate, MFMailComposeViewControllerDelegate, UIGestureRecognizerDelegate, MLSearchTaskDelegate, MLDeactivateDelegate, MLReceiptDelegate>
{
  ..........

}

- (void)create_Custom_UISlider;

main.m

- (void)viewDidLoad
{

[self create_Custom_UISlider];
[self.view addSubview: customSlider];

}

- (void)create_Custom_UISlider
{
CGRect frame = CGRectMake(20.0, 320.0, 280, 0.0);


customSlider = [[MyUISlider alloc] initWithFrame:frame];

[customSlider addTarget:self action:@selector(sliderAction:) forControlEvents:UIControlEventValueChanged];
// in case the parent view draws with a custom color or gradient, use a transparent color

customSlider.backgroundColor = [UIColor clearColor];

UIImage *stetchLeftTrack = [[UIImage imageNamed:@"blue_slider08.png"]
           stretchableImageWithLeftCapWidth: 10.0 topCapHeight:0.0];
UIImage *stetchRightTrack = [[UIImage imageNamed:@"blue_slider08.png"]
            stretchableImageWithLeftCapWidth: 260.0 topCapHeight:0.0];


[customSlider setThumbImage: [UIImage imageNamed:@"slider_button00"] forState:UIControlStateNormal];
[customSlider setMinimumTrackImage:stetchLeftTrack forState:UIControlStateNormal];
[customSlider setMaximumTrackImage:stetchRightTrack forState:UIControlStateNormal];


                    customSlider.minimumValue = 0.0;
                    customSlider.maximumValue = 1.0;
                    customSlider.continuous = NO;
                    customSlider.value = 0.00;

}

-(void) sliderAction: (UISlider *) sender{

if(sender.value !=1.0){
 [sender setValue: 0.00 animated: YES];
}
else{
[sender setValue 0.00 animated: YES];
 // add some code here depending on what you want to do!
  }
}

EDIT (trying to subclass with the code below)

MyUISlider.h

#import <UIKit/UIKit.h>

@interface MyUISlider : UISlider {

}

@end

MyUISlider.m

#import "MyUISlider.h"

@implementation MyUISlider



- (CGRect)thumbRectForBounds:(CGRect)bounds trackRect:(CGRect)rect value:(float)value
{


return CGRectInset ([super thumbRectForBounds:bounds trackRect:rect value:value], 10 , 10);

}


@end
Jesper Martensson
  • 1,238
  • 3
  • 18
  • 44
  • See my working example to the same question here: http://stackoverflow.com/a/26316371/258931 – Thomas Oct 11 '14 at 17:21
  • Possible duplicate of [Custom UISlider - Increase "hot spot" size](http://stackoverflow.com/questions/13196263/custom-uislider-increase-hot-spot-size) – Roland Keesom Jan 21 '17 at 15:24

5 Answers5

13

You have to override thumbRectForBounds:trackRect:value: in a custom subclass (instead of calling the method yourself like you do in your code, which does nothing except returning a value that you don't even bother to retrieve).

thumbRectForBounds:trackRect:value: is not a method to set the tumb rect, but to get it. The slider will internally call this thumbRectForBounds:trackRect:value: method to know where to draw the thumb image, so you need to override it — as explained in the documentation — to return the CGRect you want (so that it will be 35x35px as you wish).

AliSoftware
  • 32,623
  • 6
  • 82
  • 77
  • Ive tried different approaches but failed. Probably because I am bad and doing something wrong. Ive edited my code above, could you please show (fill in or fix the code) and show how you would have done it? If not, thx for your help. You have at least pointed me in the right direction.... – Jesper Martensson Aug 12 '13 at 03:32
  • 2
    You have the right code structure. All you need is to implement the method to return the correct `CGRect` according to the `trackRect` and `value` (as the thumb is at a different position depending on the slider value of course), as explained in the doc. Just some simple math to do. And of course write `customSlider = [[MyUISlider alloc] initWithFrame:frame];` in your `create_Custom_UISlider` method, to instanciate a `MyUISlider` and not a standard `UISlider`. – AliSoftware Aug 12 '13 at 09:42
  • Thanx for you answer Ali. I forgot to change the code to the MyUISlider alloc.. But what I don't understand is how I should structure the code in the method: - (CGRect)thumbRectForBounds:(CGRect)bounds trackRect:(CGRect)rect value:(float)value { ?????? } to return something useful that works. I understand you can not give me exact numbers, but what would you put in this method if you look at the rest of my code? Thanx once more for your help! – Jesper Martensson Aug 13 '13 at 05:29
  • 2
    Why not simply rely on the `super` implementation, and simply return `CGRectInset([super thumbRectForBounds:bounds trackRect:rect value:value], -10, -10)` to have a rectangle 10x10 larger than the one used by the `UISlider` superclass for example? – AliSoftware Aug 13 '13 at 08:43
  • I did what you said and tried other things aswell. I am still not able to make it work. I have edited/updated the code above so you can see what I tried last time. I have also made some screens to demonstrate what it looks like currently with the latest code and before I subclassed it here: http://tinypic.com/view.php?pic=347dufa&s=5 – Jesper Martensson Aug 13 '13 at 23:52
  • 2
    There seems to be an error in the implementation of `thumbRectForBounds...`. There is no `return` statement before the `CGRectInset` call. You should have: `return CGRectInset ([super thumbRectForBounds:bounds trackRect:rect value:value], -10 , -10);` – Desmond Aug 23 '13 at 12:04
  • Thank you @AliSoftware - I was tearing my hair out on this! – amergin May 25 '14 at 14:56
13

Updated for Swift 3.0 and iOS 10

private func generateHandleImage(with color: UIColor) -> UIImage {
    let rect = CGRect(x: 0, y: 0, width: self.bounds.size.height + 20, height: self.bounds.size.height + 20)

    return UIGraphicsImageRenderer(size: rect.size).image { (imageContext) in
        imageContext.cgContext.setFillColor(color.cgColor)
        imageContext.cgContext.fill(rect.insetBy(dx: 10, dy: 10))
    }
}

Calling:

self.sliderView.setThumbImage(self.generateHandleImage(with: .white), for: .normal)

Original answer:

By far the easiest method is just to increase the size of the thumb image with invisible border around it:

- (UIImage *)generateHandleImageWithColor:(UIColor *)color
{
    CGRect rect = CGRectMake(0.0f, 0.0f, self.bounds.size.height + 20.f, self.bounds.size.height + 20.f);
    UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0.f);
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetFillColorWithColor(context, color.CGColor);
    CGContextFillRect(context, CGRectInset(rect, 10.f, 10.f));

    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return image;
}

And than adding this image to slider:

[self.sliderView setThumbImage:[self generateHandleImageWithColor:[UIColor redColor]] forState:UIControlStateNormal];
matto1990
  • 3,766
  • 2
  • 27
  • 32
Borut Tomazin
  • 8,041
  • 11
  • 78
  • 91
1

I also had this problem and solved it by overriding

-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event

method. You can return YES for those points, that you want to be touched.

Yerkezhan
  • 481
  • 5
  • 9
0

You can check my double slider project

In summary, I implemented the hit test method so the beginTrackingWithTouch is invoked.

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    if (CGRectContainsPoint(self.leftHandler.frame, point) || CGRectContainsPoint(self.rightHandler.frame, point)) {
        return self;
    }

    return [super hitTest:point withEvent:event];
}

Check the class for further details

Raphael Oliveira
  • 7,751
  • 5
  • 47
  • 55
-1

why you wanna go for custom slider while you can change the area of a default slider ;)

take a look at this code it worked for me to increase the touch area of my UISlider hope it helps you too

CGRect sliderFrame = yourSlider.frame;
sliderFrame.size.height = 70.0;
[yourSlider setFrame:sliderFrame];
D-eptdeveloper
  • 2,430
  • 1
  • 16
  • 30