Custom UISlider - Increase "hot spot" size
Asked Answered
B

7

19

I have a custom UISlider that is relatively tough for big fingered people to grab hold of and slide due to the size of the "thumb image". Is there any way to increase the size of clickable / draggable area without altering the size of the image?

Here's the code I have for creating the custom slider if that helps:

[slider setMaximumTrackImage:[[UIImage imageNamed:@"max.png"]
                                             resizableImageWithCapInsets:UIEdgeInsetsMake(0, 20, 0, 20)]
                                   forState:UIControlStateNormal];
[slider setMinimumTrackImage:[[UIImage imageNamed:@"min.png"]
                                             resizableImageWithCapInsets:UIEdgeInsetsMake(0, 20, 0, 20)]
                                   forState:UIControlStateNormal];
[slider setThumbImage:[UIImage imageNamed:@"thumb.png"]
                            forState:UIControlStateNormal];
Boulogne answered 2/11, 2012 at 13:32 Comment(4)
You could cheat - add a border of transparent pixels around your thumb image - that would increase it's size without it looking any different :)Interradial
If I did that, I wouldn't be able to set the slider to 0 or 1. (Like it would be set to zero, but it wouldn't look like it is due to the transparent border on the left/right side of the image.)Boulogne
So add padding to the left/right sides of your track images as well. Then, compensate for not being able to quite get to 0 or 1 in your code.Interradial
go with this link erfan-ali-31.blogspot.in/2011/10/… its working, tested in device alsoFlowing
B
27

I ended up subclassing the UISlider and overriding this method:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event {
    CGRect bounds = self.bounds;
    bounds = CGRectInset(bounds, -10, -15);
    return CGRectContainsPoint(bounds, point);
}

This extends the touchable area by 10 pixels on the left and right and 15 pixels on the top and bottom.

Boulogne answered 15/11, 2012 at 20:10 Comment(2)
This seemed to work well on iOS7. I wanted to thicken the track for bounds so I subclassed UISlider and reimplemented (CGRect)trackRectForBounds:(CGRect)bounds, but then the clickable area was very small. The above fixed this issueBono
This doesn't seem to take effect on iOS6, but works on iOS7. Any suggestions for iOS 6 support?Rosalba
C
8

This solution works with iOS 8:

class ExtUISlider: UISlider {

    var thumbTouchSize : CGSize = CGSizeMake(50, 50)

    override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool {
        let bounds = CGRectInset(self.bounds, -thumbTouchSize.width, -thumbTouchSize.height);
        return CGRectContainsPoint(bounds, point);
    }

    override func beginTrackingWithTouch(touch: UITouch, withEvent event: UIEvent) -> Bool {
        let thumbPercent = (value - minimumValue) / (maximumValue - minimumValue)
        let thumbSize = thumbImageForState(UIControlState.Normal)!.size.height
        let thumbPos = CGFloat(thumbSize) + (CGFloat(thumbPercent) * (CGFloat(bounds.size.width) - (2 * CGFloat(thumbSize))))
        let touchPoint = touch.locationInView(self)

        return (touchPoint.x >= (thumbPos - thumbTouchSize.width) &&
            touchPoint.x <= (thumbPos + thumbTouchSize.width))
    }
}

Credits go to this post: http://www.mpatric.com/2009-04-15-more-responsive-sliders-on-the-iphone

Conquian answered 11/10, 2014 at 15:44 Comment(2)
thumbImageForState(UIControlState.Normal) can return nil if not using a custom image as posted at :#21314296. Subclassing, as sugested by Rudolf Adamkovic, solves the problem of getting the thumb size.Hypo
Thank you Thomas! This answer helped me big time!Pokelogan
C
8

Swift 3

Subclass of UISlider with increased touch area

class CustomSlider: UISlider {

    private var thumbTouchSize = CGSize(width: 40, height: 40)

    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        let increasedBounds = bounds.insetBy(dx: -thumbTouchSize.width, dy: -thumbTouchSize.height)
        let containsPoint = increasedBounds.contains(point)
        return containsPoint
    }

    override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
        let percentage = CGFloat((value - minimumValue) / (maximumValue - minimumValue))
        let thumbSizeHeight = thumbRect(forBounds: bounds, trackRect:trackRect(forBounds: bounds), value:0).size.height
        let thumbPosition = thumbSizeHeight + (percentage * (bounds.size.width - (2 * thumbSizeHeight)))
        let touchLocation = touch.location(in: self)
        return touchLocation.x <= (thumbPosition + thumbTouchSize.width) && touchLocation.x >= (thumbPosition - thumbTouchSize.width)
    }
}
Contentment answered 20/1, 2017 at 20:16 Comment(0)
D
3

I ended up using this and it works pretty well for me.

Posted this answer, so that it could be helpful to someone.

import UIKit

class CustomSlider: UISlider {

/*
// Only override draw() if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func draw(_ rect: CGRect) {
    // Drawing code
}
*/
// Increase slider height
   override func trackRect(forBounds bounds: CGRect) -> CGRect {
    let customBounds: CGRect = CGRect(origin: bounds.origin, size: CGSize(width: bounds.size.width, height: 5.0))
    return customBounds
}



override func thumbRect(forBounds bounds: CGRect, trackRect rect: CGRect, value: Float) -> CGRect {
    return super.thumbRect(
        forBounds: bounds, trackRect: rect, value: value)


}

// Increase Thumb hot spot clickable area
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
    var bounds: CGRect = self.bounds
    bounds = bounds.insetBy(dx: -10, dy: -10);
    return bounds.contains(point);

}

override func awakeFromNib() {
    // Configure Volume slider
    let thumbImageNormal = UIImage.init(named:"thumb")
    self.setThumbImage(thumbImageNormal, for: .normal)

    super.awakeFromNib()
}

}
Debenture answered 9/9, 2016 at 12:45 Comment(0)
K
1

Also you can just increese image size which will lead to increasing of slider thumb size.

  1. If you need to left image size not too big but adjust slider size just add transparent space around image content. enter image description here

  2. If you are using slider in UITableViewCell the problem also is that tableview handle gesture just before the slider. To change this use the following solution: https://mcmap.net/q/589818/-uitableview-cell-with-slider-touch-not-working-correctly-swift-2 I think it is not too difficult to translate his code to Objective C.

Ker answered 22/11, 2016 at 8:23 Comment(1)
I don't think the spacing in image can work, the scrubber within the image would never fully touch the left or ride side of sliders because of the spacing.Sarpedon
D
0

Here's a modified version of Thomas's original answer

Swift 4 and Swift 5

class IncreasedAreaSlider: UISlider {
    
    let thumbTouchSize = CGSize(width: 50, height: 50)
    
    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        let bounds = self.bounds.insetBy(dx: -thumbTouchSize.width, dy: -thumbTouchSize.height)
        return bounds.contains(point)
    }
    
    override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
        let thumbPercent = (value - minimumValue) / (maximumValue - minimumValue)
        let thumbSize = thumbImage(for: .normal)!.size.height
        let thumbPos = CGFloat(thumbSize) + (CGFloat(thumbPercent) * (CGFloat(bounds.size.width) - (2 * CGFloat(thumbSize))))
        let touchPoint = touch.location(in: self)
        
        return (touchPoint.x >= (thumbPos - thumbTouchSize.width) &&
                touchPoint.x <= (thumbPos + thumbTouchSize.width))
    }
}
Dogy answered 19/6 at 8:28 Comment(0)
H
-1

Resize frame and change image alignment to desired one. You can make its alignment centred, left, right, top or bottom. Make it this way:

CGRect newFrame = sliderHandle.frame;
CGRectSetWidth(newFrame, 80);
CGRectSetHeight(newFrame, 80);
[sliderHandle setFrame:newFrame];
[sliderHandle setContentMode:UIViewContentModeCenter];

So your touching frame will be bigger and image scale will remain unchanged.

Hellbender answered 7/11, 2012 at 13:38 Comment(2)
This just adjusts the visible height and width of the slider, it doesn't increase the touch area.Boulogne
You can also resize actual slider's view, which gathers touchesHellbender

© 2022 - 2024 — McMap. All rights reserved.