Search code examples
iosios7uigesturerecognizeruisliderhittest

UIPageViewController with UISlider inside controller - increase hit area of slider


I have multiple controllers in my PageViewController and in one controller I have a few sliders. Now there is a problem that user must touch exactly slider circle (I am not sure about right expression, thumb? - that moving part) and I would like to increase area in which reacts slider and not the whole PageViewController. I tried these solutions but it doesn't help:

  • thumbRectForBounds:

    - (CGRect)thumbRectForBounds:(CGRect)bounds trackRect:(CGRect)rect value:(float)value
    {
        return CGRectInset ([super thumbRectForBounds:bounds trackRect:rect value:value], 15, 15);
    }
    
  • Increase hitTest area:

    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
        if (CGRectContainsPoint(CGRectInset(self.frame, 200, 200), point) || CGRectContainsPoint(CGRectInset(self.frame, 200, 200), point)) {
             return self;
        }
        return [super hitTest:point withEvent:event];
    }
    

I have these methods in my custom slider class because I would like to reuse this. Last thing what I found and not tried yet is create some object layer over slider which "takes" gesture and disable PageViewController but I am not sure how to do it and I am not sure if it's good/best solution.


Solution

  • I am not a big fan of the UISlider component because as you noticed, it is not trivial to increase the hit area of the actual slider. I would urge you to replicate the UISlider instead using a pan gesture for a much better user experience:

    i. create a slider background with a seperate UIImageView with a slider image. ii. create the PanGesture:

    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:);
    [imageView addGestureRecognizer:pan];
    

    iii. implement handlePan Method:

    - (IBAction)handlePan:(UIPanGestureRecognizer *)recognizer {
    
        //pan (slide) begins
        CGPoint translation = [recognizer locationInView:self.view];
        translation.y = self.slideImage.center.y;
        self.slideImage.center = translation;
    
        if(recognizer.state == UIGestureRecognizerStateEnded) {
            LTDebugLog(@"\n\n PAN, with spot: %f\n\n", self.slideImage.center.x);
            //do something after user is done sliding
        }
    }
    

    The big benefit of this method is that you will have a much better user experience as you can make the responsive UIImageView as big as you want.

    Alternatively, you could subclass a UISlider and increase the hit space there, although in my experience this gives mixed results.

    Hope this helps