拇指图像不会移动到 UISlider 的边缘

Posted

技术标签:

【中文标题】拇指图像不会移动到 UISlider 的边缘【英文标题】:Thumb image does not move to the edge of UISlider 【发布时间】:2014-02-26 13:26:42 【问题描述】:

即使它的值为最大值或最小值,拇指图像也不会移动到边缘。

有谁知道如何让它一直移动到滑块的边缘?

@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】:

您看到的是 UISlider 显然按设计工作。

默认情况下,在极值处,拇指的边缘与轨道的边缘对齐,而不是拇指的中心位于轨道的边缘。因此,如果您提供的缩略图图像的左右边缘不是不透明的,那么这是一个问题,因为这样下面的轨道就会变得可见。

一个部分修复是覆盖thumbRectForBounds(_:trackRect:value:),以便拇指的中心范围跨越滑块的宽度。下面的代码显示了这一点:

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)
  

但是,我会说这只是一个部分修复,因为我不相信这也会修改拇指点击区域的位置,所以上面的修复有一个不幸的副作用是拇指比默认情况下更不容易触摸,因为滑块仍然会更靠近滑块的中心侦听触摸。

【讨论】:

我相信你想乘以 CGFloat((value - self.minimumValue) / (self.maximumValue - self.minimumValue)) 而不是 CGFloat(value / (self.maximumValue - self.minimumValue) )) 考虑非零值【参考方案2】:

我最近不得不处理滑块的自定义(子类),包括在滑块上添加刻度线。拇指图像不以该值为中心,并且由于您替换了图像,因此根据实现,它位于应有的位置。 为了做你想做的事,我不得不使用

调整拇指图像的位置
- (CGRect)thumbRectForBounds:(CGRect)bounds trackRect:(CGRect)rect value:(float)value

【讨论】:

【参考方案3】:

如果没有更改,最受好评的答案对我不起作用。这就是所做的——它是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
    

【讨论】:

【参考方案4】:

代替

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

尝试像这样设置外观代理

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

【讨论】:

【参考方案5】:

您会看到它已经移动到滑块的边缘。这是因为拇指图像滑块有这样的角落,所以你感觉它没有移动到边缘。

如果您想确认这一点,请尝试与拇指图像中的方形图像相同的代码。

希望对你有帮助。

【讨论】:

【参考方案6】:

它可能不是最有效的,但它似乎工作正常。这是在 Objective-C 中实现它的另一种简单方法。基本上,您将使用“pixelAdjustment”变量来获得所需的滑块。

- (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】:

我通过继承 UISlider 创建了类似的滑块。 在情节提要中,如果滑块拇指未获得触摸事件,您可以设置高度约束以在运行时增加高度。

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】:

我找到了一个更简单的解决方案,它也有一个非常流畅的用户体验。

我基本上只是将.highlighted 图像设置为与.normal 相同的值。这是代码。

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

【讨论】:

【参考方案9】:

所以我对这个问题的解决方案是让滑块的颜色 Min Track 和 Max Track 透明,然后在 initWithCoder 中绘制一个新的轨道,并在 continueTrackingWithTouch 中更新轨道的大小。

-(AnalogueSlider *)initWithCoder:(NSCoder *)coder :(NSArray *)labels 
    self = [super initWithCoder:coder];

    trackRect = [self trackRectForBounds:self.bounds];
    thumbRect = [self thumbRectForBounds:self.bounds trackRect:trackRect value:self.value];

    // drawn a new track
    leftTrack = [[UIView alloc] initWithFrame:CGRectMake(trackRect.origin.x+thumbRect.size.width/2.0, trackRect.origin.y, thumbRect.origin.x-thumbRect.size.width, trackRect.size.height)];
    leftTrack.backgroundColor = [UIColor blueColor];
    [self insertSubview:leftTrack belowSubview:self];

    rightTrack = [[UIView alloc] initWithFrame:CGRectMake(thumbRect.origin.x+thumbRect.size.width/2.0, trackRect.origin.y, trackRect.size.width-thumbRect.origin.x, trackRect.size.height)];
    rightTrack.backgroundColor = [UIColor grayColor];
    [self insertSubview:rightTrack belowSubview:self];

    return self;


-(BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event 
    thumbRect = [self thumbRectForBounds:self.bounds trackRect:trackRect value:self.value];
    leftTrack.frame = CGRectMake(trackRect.origin.x+thumbRect.size.width/2.0, trackRect.origin.y, thumbRect.origin.x-thumbRect.size.width, trackRect.size.height);
    rightTrack.frame = CGRectMake(thumbRect.origin.x+thumbRect.size.width/2.0, trackRect.origin.y, trackRect.size.width-thumbRect.origin.x, trackRect.size.height);

    return [super continueTrackingWithTouch:touch withEvent:event];

这允许拇指图像比轨道移动得更远,因此拇指的中心位于轨道的末端。

最后:

【讨论】:

以上是关于拇指图像不会移动到 UISlider 的边缘的主要内容,如果未能解决你的问题,请参考以下文章

在透明拇指图像后面隐藏 UISlider 轨道

拖出滑块时,UISlider 选择的拇指图像不会保留

UISlider 拇指图像像素化

Objective C UISlider 仅更改最小轨迹图像

是否可以向 UISlider 拇指图像添加标签?

自定义 UI 滑块,拇指图像大小问题