Thumb image does not move to the edge of UISlider

一笑奈何 提交于 2019-12-09 15:16:03

问题


Thumb image does not move to the edge even when it's value is max or min.

Does anyone know how to make it move all the way to the edge of the slider?

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UISlider *slider;
@end

@implementation ViewController
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
UIImage* sliderBarMinImage = [[UIImage imageNamed:@"slider_bar_3_min"] stretchableImageWithLeftCapWidth:8.0 topCapHeight:0.0];
UIImage* sliderBarImage = [[UIImage imageNamed:@"slider_bar_3_max"] stretchableImageWithLeftCapWidth:8.0 topCapHeight:0.0];
UIImage* sliderThumbImage= [[UIImage imageNamed:@"slider_thumb_3"] stretchableImageWithLeftCapWidth:8.0 topCapHeight:0.0];

[self.slider setMinimumTrackImage:sliderBarMinImage forState:UIControlStateNormal];
[self.slider setMaximumTrackImage:sliderBarImage forState:UIControlStateNormal];
[self.slider setThumbImage:sliderThumbImage forState:UIControlStateNormal];
}
@end

回答1:


What you see is the UISlider working as designed, apparently.

By default, at the extreme values, the thumb's edge is aligned with the edges of the track, rather than the thumb's center being positioned on the edge of the track. So this is a problem if you provide a thumb image whose left and right edges are not opaque, since then the track underneath becomes visible.

One partial fix is to override thumbRectForBounds(_:trackRect:value:), so that the thumbs' centers range across the width of the slider. The code below shows this:

class CenteredThumbSlider : UISlider {
  override func thumbRectForBounds(bounds: CGRect, trackRect rect: CGRect, value: Float) -> CGRect
  {
    let unadjustedThumbrect = super.thumbRectForBounds(bounds, trackRect: rect, value: value)
    let thumbOffsetToApplyOnEachSide:CGFloat = unadjustedThumbrect.size.width / 2.0
    let minOffsetToAdd = -thumbOffsetToApplyOnEachSide
    let maxOffsetToAdd = thumbOffsetToApplyOnEachSide
    let offsetForValue = minOffsetToAdd + (maxOffsetToAdd - minOffsetToAdd) * CGFloat(value / (self.maximumValue - self.minimumValue))
    var origin = unadjustedThumbrect.origin
    origin.x += offsetForValue
    return CGRect(origin: origin, size: unadjustedThumbrect.size)
  }
}

However, I would say this is only a partial fix since I do not believe this also modifies the position of the thumb's tap region, so this fix above has the unfortunate side-effect of making the thumbs even less easy to touch than they are by default, since the slider still listens for touches more toward the center of the slider.




回答2:


I recently had to deal with customization of the slider (subclassed), including adding tickmarks on the slider. Thumb image is not centered on the value and since you replaced image it is positioned where it is supposed to be according to implementation. In order to do what you are trying to do I had to adjust position of the thumb image using

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



回答3:


Instead of

[self.slider setMinimumTrackImage:sliderBarMinImage forState:UIControlStateNormal];
[self.slider setMaximumTrackImage:sliderBarImage forState:UIControlStateNormal];
[self.slider setThumbImage:sliderThumbImage forState:UIControlStateNormal];

Try setting the appearance proxy like this

[[UISlider appearance] setMinimumTrackImage:sliderBarMinImage forState:UIControlStateNormal];
[[UISlider appearance] setMaximumTrackImage:sliderBarImage forState:UIControlStateNormal];
[[UISlider appearance] setThumbImage:sliderThumbImage forState:UIControlStateNormal];



回答4:


It you see it already moves to the edge of the Slider. Its because thumb image slider have such corner so you feel like its not moving to the edge.

If you want to confirm this that try out the same code with Square image in the thumb image.

I hope it will help you.




回答5:


Most upvoted answer didn't work for me without changes. Here's what did -- it's a drop in replacement for UISlider:

class Slider: UISlider {

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

            var thumbRect = super.thumbRect(forBounds: bounds, trackRect: rect, value: value)

            //determine value dependent offset
            var offsetForValue: CGFloat = 0
            if value != 0 {offsetForValue = thumbRect.size.width * CGFloat(value / (self.maximumValue - self.minimumValue)) - ((value > 0) ? 2 : -2)}

            //apply offset to thumb rect
            thumbRect.origin.x += offsetForValue

            return thumbRect
    }
}



回答6:


It may not be the most efficient, but it seems to work fine. This is another simple way to do it in Objective-C. Basically, you'll play around with the "pixelAdjustment" variable to get the slider where you want it.

- (CGRect)thumbRectForBounds:(CGRect)bounds trackRect:(CGRect)rect value:   (float)value {
    float multValue = value - 0.5;
    float pixelAdjustment = 30; //This is the value you need to change depending on the size of the thumb image of your slider.
    float xOriginDelta = (multValue * (bounds.size.width - pixelAdjustment));

    CGRect adjustedRect = CGRectMake(bounds.origin.x + xOriginDelta, bounds.origin.y, bounds.size.width, bounds.size.height);
    return adjustedRect;
}



回答7:


I have created the similar slider by subclassing UISlider. In storyboard you can set a height constraint to increase height at runtime if slider thumb not gets touch events.

static float const SLIDER_OFFSET = 10.0;

//Get thumb rect for larger track rect than actual to move slider to edges
    -(CGRect)thumbRectForBounds:(CGRect)bounds trackRect:(CGRect)rect value:(float)value {
        UIImage *image = self.currentThumbImage;

    rect.origin.x -= SLIDER_OFFSET;
    rect.size.width += (SLIDER_OFFSET*2);
    CGRect thumbRect = [super thumbRectForBounds:bounds trackRect:rect value:value];
    return CGRectMake(thumbRect.origin.x, rect.origin.y+2, image.size.width, image.size.height);
}

//Make track rect smaller than bounds
-(CGRect)trackRectForBounds:(CGRect)bounds  {
    bounds.origin.x += SLIDER_OFFSET;
    bounds.size.width -= (SLIDER_OFFSET*2);
    CGRect trackRect = [super trackRectForBounds:bounds];

    return CGRectMake(trackRect.origin.x, trackRect.origin.y, trackRect.size.width, trackRect.size.height);
}



回答8:


I found a simpler solution which also has a quite smooth UX.

I basically just set the .highlighted image to the same value as that of the .normal. Here's the code.

    seekBar.setThumbImage(thumbImage, for: .normal)
    seekBar.setThumbImage(thumbImage, for: .highlighted)


来源:https://stackoverflow.com/questions/21520940/thumb-image-does-not-move-to-the-edge-of-uislider

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!