【问题标题】:How to get the center of the thumb image of UISlider如何获取 UISlider 的拇指图像的中心
【发布时间】:2009-11-11 10:45:55
【问题描述】:

我正在创建一个自定义 UISlider 来测试一些界面创意。主要基于使拇指图像更大。

我发现了如何做到这一点,就像这样:

UIImage *thumb = [UIImage imageNamed:@"newThumbImage_64px.png"];  
[self.slider setThumbImage:thumb forState:UIControlStateNormal];  
[self.slider setThumbImage:thumb forState:UIControlStateHighlighted];  
[thumb release];  

要计算相关值,我需要知道拇指图像的中心点在被操作时落在哪里。并且该点应该在它的superview的坐标中。

查看 UISlider 文档,我没有看到任何跟踪此内容的属性。

是否有一些简单的方法来计算它或者它可以从一些现有的值中推导出来?

【问题讨论】:

    标签: iphone cocoa-touch user-interface uislider


    【解决方案1】:

    斯威夫特 3

    extension UISlider {
        var thumbCenterX: CGFloat {
            let trackRect = self.trackRect(forBounds: frame)
            let thumbRect = self.thumbRect(forBounds: bounds, trackRect: trackRect, value: value)
            return thumbRect.midX
        }
    }
    

    【讨论】:

      【解决方案2】:

      这将返回 UISlider 拇指图像中心在视图坐标中的正确 X 位置:

      - (float)xPositionFromSliderValue:(UISlider *)aSlider {
           float sliderRange = aSlider.frame.size.width - aSlider.currentThumbImage.size.width;
           float sliderOrigin = aSlider.frame.origin.x + (aSlider.currentThumbImage.size.width / 2.0);
      
           float sliderValueToPixels = (((aSlider.value - aSlider.minimumValue)/(aSlider.maximumValue - aSlider.minimumValue)) * sliderRange) + sliderOrigin;
      
           return sliderValueToPixels;
      }
      

      把它放在你的视图控制器中并像这样使用它:(假设属性名为滑块)

      float x = [self xPositionFromSliderValue:self.slider];
      

      【讨论】:

      • 这对我有用,除了需要进行一项更改以允许具有自定义最小/最大值的滑块:float sliderValueToPixels = (aSlider.value/aSlider.maximumValue * sliderRange) + sliderOrigin;此外,它是这样调用的:float x = [self xPositionFromSliderValue:someSlider];
      • 完美结合詹姆斯的修改
      • 实际上,为了容纳一个不为 0(或接近它)的自定义最小值,您需要将其更改为:float sliderValueToPixels = (((aSlider.value-aSlider.minimumValue )/(aSlider.maximumValue-aSlider.minimumValue)) * sliderRange) + sliderOrigin;
      • 谢谢乔尔!您的附加代码对我有帮助,因为我有一个自定义的最小值和最大值。
      • 如果 UISlider 有默认的拇指图像,那么 currentThumbImage 返回 nil。在这种情况下如何计算宽度?编辑:我自己回答,默认拇指图像等于滑块高度。
      【解决方案3】:

      我通过首先以百分比映射 UISlider 的值间隔然后将滑块大小的相同百分比减去拇指大小的百分比来接近它,我将这个值加上拇指大小的一半以获得它的中心。

          - (float)mapValueInIntervalInPercents: (float)value min: (float)minimum max: (float)maximum
          {
              return (100 / (maximum - minimum)) * value -
                     (100 * minimum)/(maximum - minimum);
          }    
      
      
          - (float)xPositionFromSliderValue:(UISlider *)aSlider
          {
              float percent = [self mapValueInIntervalInPercents: aSlider.value
                                    min: aSlider.minimumValue
                                    max: aSlider.maximumValue] / 100.0;
      
              return percent * aSlider.frame.size.width -
                     percent * aSlider.currentThumbImage.size.width +
                     aSlider.currentThumbImage.size.width / 2;
          }
      

      【讨论】:

        【解决方案4】:

        我在阅读上述建议后尝试了这个 -

        yourLabel = [[UILabel alloc]initWithFrame:....];
        
        //Call this method on Slider value change event
        
        -(void)sliderValueChanged{
            CGRect trackRect = [self.slider trackRectForBounds:self.slider.bounds];
            CGRect thumbRect = [self.slider thumbRectForBounds:self.slider.bounds
                                       trackRect:trackRect
                                           value:self.slider.value];
        
            yourLabel.center = CGPointMake(thumbRect.origin.x + self.slider.frame.origin.x,  self.slider.frame.origin.y - 20);
        }
        

        对于 Swift 版本

        func sliderValueChanged() -> Void {
                let trackRect =  self.slider.trackRect(forBounds: self.slider.bounds)
                let thumbRect = self.slider.thumbRect(forBounds: self.slider.bounds, trackRect: trackRect, value: self.slider.value)
                yourLabel.center = CGPoint(x: thumbRect.origin.x + self.slider.frame.origin.x + 30, y: self.slider.frame.origin.y - 60)
            }
        

        我可以通过使用这个 sn-p 获得最准确的值。

        【讨论】:

          【解决方案5】:

          Swift 3.0
          喜欢请参考。

          import UIKit
          
          extension UISlider {
          
              var trackBounds: CGRect {
                  return trackRect(forBounds: bounds)
              }
          
              var trackFrame: CGRect {
                  guard let superView = superview else { return CGRect.zero }
                  return self.convert(trackBounds, to: superView)
              }
          
              var thumbBounds: CGRect {
                  return thumbRect(forBounds: frame, trackRect: trackBounds, value: value)
              }
          
              var thumbFrame: CGRect {
                  return thumbRect(forBounds: bounds, trackRect: trackFrame, value: value)
              }
          }
          

          【讨论】:

            【解决方案6】:

            最好改用-[UIView convertRect:fromView:] 方法。无需任何复杂计算,更简洁:

            - (IBAction)scrub:(UISlider *)sender
            {
                CGRect _thumbRect = [sender thumbRectForBounds:sender.bounds
                                                    trackRect:[sender trackRectForBounds:sender.bounds]
                                                        value:sender.value];
                CGRect thumbRect = [self.view convertRect:_thumbRect fromView:sender];
            
                // Use the rect to display a popover (pre iOS 8 code)
                [self.popover dismissPopoverAnimated:NO];
                self.popover = [[UIPopoverController alloc] initWithContentViewController:[UIViewController new]];
                [self.popover presentPopoverFromRect:thumbRect inView:self.view
                            permittedArrowDirections:UIPopoverArrowDirectionDown|UIPopoverArrowDirectionUp animated:YES];
            }
            

            【讨论】:

            • 这是确定的答案。无需继承 UISlider。谢谢你
            【解决方案7】:

            我想知道为什么你们都没有提供最简单的答案,即阅读手册。您可以准确地计算所有这些值,并确保它们保持不变,只需使用以下方法:

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

            您可以在开发者文档中轻松找到。

            如果拇指图像发生变化并且您想要更改其定位方式,则您可以继承并覆盖这些方法。第一个给出了拇指可以移动的矩形,第二个给出了拇指本身的位置。

            【讨论】:

            • 这是明确的答案!只需更新一个包含 [super trackRectForBounds] 返回值的成员变量,就可以跳过所有计算。太棒了!
            • 文档说这两种方法:“你不应该直接调用这个方法。”
            【解决方案8】:

            在玩了一点 IB 和 1px 宽的拇指图像后,拇指的位置正是您所期望的:

            UIImage       *thumb = [UIImage imageNamed:@"newThumbImage_64px.png"];  
            CGRect        sliderFrame = self.slider.frame;
            CGFloat       x = sliderFrame.origin.x + slideFrame.size.width * slider.value + thumb.size.width / 2;
            CGFloat       y = sliderFrame.origin.y + sliderFrame.size.height / 2;
            
            return CGPointMake(x, y);
            

            【讨论】:

            • 假设滑块范围为 0..1,当slider.value 为0 时,您的观点是正确的,但随着slider.value 的变化,您的观点会变得更多。此外,x 等式中有一个错字。
            • 另外,sliderFrame.x 不应该是sliderFrame.origin.x & sliderFrame.size.width?
            • 糟糕,对错字表示抱歉,已修复。
            • 仍然没有得到正确的值。测试时,我使用您计算的 x,y 点设置透明视图的中心点。
            • 经过进一步测试,似乎有 1-4 像素的调整,具体取决于您在滑块上的位置。我在这里发布了我的测试代码:dl.dropbox.com/u/85235/ThumbTest.zip。使用它和 xScope,您可以四处寻找确切的值。
            【解决方案9】:

            这是一个 Swift 2.2 解决方案,我为它创建了一个扩展。我只用默认图像尝试过这个。

            import UIKit
            
            extension UISlider {
            
                var thumbImageCenterX: CGFloat {
                    let trackRect = trackRectForBounds(bounds)
                    let thumbRect = thumbRectForBounds(bounds, trackRect: trackRect, value: value)
            
                    return thumbRect.origin.x + thumbRect.width / 2 - frame.size.width / 2
                }
            }
            

            【讨论】:

              【解决方案10】:

              当 UISlider 水平时,上述解决方案很有用。在最近的一个项目中,我们需要使用带角度的 UISlider。所以我需要同时获得 x 和 y 位置。使用下面来计算 x,y 轴:

              - (CGPoint)xyPositionFromSliderValue:(UISlider *)aSlider WithAngle:(double)aangle{
                 //aangle means the dextrorotation angle compare to horizontal.
                 float xOrigin = 0.0;
                 float yOrigin = 0.0;
                 float xValueToaXis=0.0;
                 float yValueToaXis=0.0;
                 float sliderRange = slider_width-aSlider.currentThumbImage.size.width;
                 xOrigin = aSlider.frame.origin.x+slider_width*fabs(cos(aangle/180.0*M_PI));
                 yOrigin = aSlider.frame.origin.y;
              
                 xValueToaXis = xOrigin + ((((((aSlider.value-aSlider.minimumValue)/(aSlider.maximumValue-aSlider.minimumValue)) * sliderRange))+(aSlider.currentThumbImage.size.width / 2.0))*cos(aangle/180.0*M_PI)) ;
                 yValueToaXis =  yOrigin + ((((((aSlider.value-aSlider.minimumValue)/(aSlider.maximumValue-aSlider.minimumValue)) * sliderRange))+(aSlider.currentThumbImage.size.width / 2.0))*sin(aangle/180.0*M_PI));
              
                 CGPoint xyPoint=CGPointMake(xValueToaXis, yValueToaXis);
                 return xyPoint;
              }
              

              另外,我可以基于 UISlider 创建 Ranger Slider 吗?谢谢。

              【讨论】:

                【解决方案11】:

                这适用于放置在屏幕上任何位置的 UISlider。大多数其他解决方案仅在 UISlider 与屏幕左边缘对齐时才有效。请注意,我使用 frame 而不是 bounds 作为 thumbRect 来实现这一点。我展示了两个变体,基于使用 framebounds 作为 trackRect

                extension UISlider {
                
                    //this version will return the x coordinate in relation to the UISlider frame
                    var thumbCenterX: CGFloat {
                        return thumbRect(forBounds: frame, trackRect: trackRect(forBounds: bounds), value: value).midX
                    }
                
                    //this version will return the x coordinate in relation to the UISlider's containing view
                    var thumbCenterX: CGFloat {
                        return thumbRect(forBounds: frame, trackRect: trackRect(forBounds: frame), value: value).midX
                    }
                
                }
                

                【讨论】:

                  【解决方案12】:

                  第 1 步:获取检测位置的视图(使用与#Ovi Bortas 相同的扩展顶部commet)

                  @IBOutlet 弱变量滑块视图:UIView!

                  第二步:为添加子视图设置标签框 func setLabelThumb(slider:UISlider,value:Float){ slider.value = 值

                  let label = UILabel(frame:  CGRect(x: slider.thumbCenterX - 20, y: slider.frame.origin.y - 25, width: 50, height: 30))
                  label.font = UIFont.systemFont(ofSize: 10.0)
                  label.textColor = UIColor.red
                  label.textAlignment = .center
                  label.text = "\(value) kg."
                  
                  sliderView.addSubview(label)
                  

                  }

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2018-01-04
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2017-06-24
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多