Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/98.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios UISlider设置拇指清晰背景_Ios_Objective C_Uikit_Uislider - Fatal编程技术网

Ios UISlider设置拇指清晰背景

Ios UISlider设置拇指清晰背景,ios,objective-c,uikit,uislider,Ios,Objective C,Uikit,Uislider,如何在UISlider上设置清晰的拇指背景,使轨迹在拇指后面不可见 这就是我目前所拥有的 但是,我希望它看起来像在iOS摄像头应用程序中一样 您必须添加拇指图像,该图像只有圆形边框,而且是透明的,据我所知,这是唯一可能的选项让我们从实际操作开始,以表明这应该实现OP的目标: 简短的版本是,我使用背景的UIImage,并对其应用以下扩展以添加边框 extension UIImage { func addRoundBorder(width: CGFloat,

如何在
UISlider
上设置清晰的拇指背景,使轨迹在拇指后面不可见

这就是我目前所拥有的

但是,我希望它看起来像在iOS摄像头应用程序中一样


您必须添加拇指图像,该图像只有圆形边框,而且是透明的,据我所知,这是唯一可能的选项

让我们从实际操作开始,以表明这应该实现OP的目标:

简短的版本是,我使用背景的UIImage,并对其应用以下扩展以添加边框

extension UIImage {
    func addRoundBorder(width: CGFloat,
                        color: UIColor) -> UIImage {
        let square = CGSize(width: min(size.width, size.height) + width * 2,
                            height: min(size.width, size.height) + width * 2)
        let imageView = UIImageView(frame: CGRect(origin: .zero, size: square))
        imageView.contentMode = .center
        imageView.image = self
        imageView.layer.cornerRadius = square.width / 2
        imageView.layer.masksToBounds = true
        imageView.layer.borderWidth = width
        imageView.layer.borderColor = color.cgColor
        UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, false, scale)
        guard let context = UIGraphicsGetCurrentContext() else { return self }
        imageView.layer.render(in: context)
        let result = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return result ?? self
    }
}
然后,我引入一个我背景的
UIImage
,并调用扩展名,使用结果作为我的新缩略图

let image = UIImage(named: "circle")!.addRoundBorder(width: 3.0, color: .yellow)
slider.setThumbImage(image, for: .normal) 
虽然这只是为了演示,但我建议使用
#imageLiteral
来避免强制转换

下面的屏幕截图将OP通过iOS摄像头应用程序提供的示例图像与我实现的图像进行比较,如下所示。由于每一个的大小,苹果一号的质量允许在比较中有更好的细节

关于@Alladinian的评论,我看到的问题是背景有一个浅色纹理,而使用边框提供了一种视觉方式,可以在按钮与背景融合的地方分解。通过使用OP的背景,它似乎提供了类似的视觉效果。然而,更具挑战性的背景,如图像,肯定会暴露我的设计,并产生不良的结果

TL;博士 简而言之,
UISlider
没有简单的API可以重新创建这种行为

前提条件:根据问题,我只是演示如何使拇指透明,而不是显示轨迹。我没有试图完全重新创建相机的滑块

理想溶液 理想的解决方案是创建最小和最大轨迹图像,利用这些图像来避免填充轨迹的一部分。我说这是理想的,因为它直截了当且性能相对较好。不幸的是,
UISlider
做了两件事,阻止我们使用这种方法

  • 最大轨迹图像实际上与整个轨迹的宽度相同,但它包含在
    clipstobunds
    设置为true的视图中。将调整最大轨迹的超级视图的大小并剪辑最大轨迹,以确保它在拇指的前端永远不可见

    在整个层次结构上禁用
    clipstobunds
    ,可以让我们在视图调试器中看到这一点

  • 最小轨迹
    UIImageView
    的大小已调整,但当调用
    UISlider
    上的
    setMinimumTrackImage
    时,实际上会创建一个不同的可调整大小的图像。这一点花了一些时间才弄清楚,但可以通过检查内存地址来演示

  • 替代解决方案:更改图像以匹配值 根据我从最初的调查中学到的,我们可以随着价值的变化生成图像。这不是最有效的方法,因为它需要反复创建许多图像。但是,它符合原始问题的参数。注意,您只能使用“连续”滑块有效地执行此操作,因为它依赖于值更新。从好的方面来说,这可以很容易地扩展到绘制更有趣的轨迹图像(如相机中的图像)

    结果是,我把拇指做得很大,这样你就可以很容易地看到它是透明的

    下面是课程:

    class TransparentThumbSlider: UISlider {
    
        let thumbWidth: CGFloat = 40
    
        override init(frame: CGRect) {
            super.init(frame: frame)
    
            configure()
        }
    
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
    
            configure()
        }
    
        func configure() {
            setThumbImage(TransparentThumbSlider.thumbImage(diameter: thumbWidth, color: .blue), for: .normal)
    
            addTarget(self, action: #selector(updateTrackImages), for: .valueChanged)
    
            updateTrackImages()
        }
    
        static func thumbImage(diameter: CGFloat, color: UIColor) -> UIImage {
            let strokeWidth: CGFloat = 4
            let halfStrokeWidth = strokeWidth / 2
            let totalRect = CGRect(x: 0, y: 0, width: diameter, height: diameter)
            let strokeRect = CGRect(x: halfStrokeWidth,
                                    y: halfStrokeWidth,
                                    width: diameter - strokeWidth,
                                    height: diameter - strokeWidth)
    
            let renderer = UIGraphicsImageRenderer(size: totalRect.size)
            let image = renderer.image { context in
                context.cgContext.setStrokeColor(color.cgColor)
                context.cgContext.setLineWidth(strokeWidth)
                context.cgContext.strokeEllipse(in: strokeRect)
            }
    
            return image
        }
    
        static func trackImage(colored color: UIColor,
                               thumbWidth: CGFloat,
                               trackWidth: CGFloat,
                               value: CGFloat,
                               flipped: Bool) -> UIImage {
    
            let fraction = flipped ? 1 - value : value
            let adjustableWidth = (trackWidth - thumbWidth)
            let halfThumbWidth = thumbWidth / 2
            let fudgeFactor: CGFloat = 2
    
            var totalRect: CGRect
    
            var coloredRect: CGRect
            if flipped {
                totalRect = CGRect(x: 0, y: 0, width: trackWidth, height: 2)
                coloredRect = CGRect(
                    x: adjustableWidth * value + thumbWidth - fudgeFactor,
                    y: 0,
                    width: adjustableWidth * fraction + (halfThumbWidth - fudgeFactor),
                    height: 2)
            } else {
                totalRect = CGRect(x: 0, y: 0, width: adjustableWidth * fraction + halfThumbWidth, height: 2)
                coloredRect = CGRect(x: 0, y: 0, width: adjustableWidth * fraction, height: 2)
            }
    
            let renderer = UIGraphicsImageRenderer(size: totalRect.size)
            let image = renderer.image { context in
                context.cgContext.setFillColor(color.cgColor)
                context.fill(coloredRect)
            }
    
            return image
        }
    
        @objc func updateTrackImages() {
    
            let trackWidth = trackRect(forBounds: bounds).width
    
            let minimumImage = TransparentThumbSlider.trackImage(
                colored: .green,
                thumbWidth: thumbWidth,
                trackWidth: trackWidth,
                value: CGFloat(value),
                flipped: false)
            setMinimumTrackImage(minimumImage, for: .normal)
    
            let maximumImage = TransparentThumbSlider.trackImage(
                colored: .yellow,
                thumbWidth: thumbWidth,
                trackWidth: trackWidth,
                value: CGFloat(value),
                flipped: true)
            setMaximumTrackImage(maximumImage, for: .normal)
        }
    
        var previousBounds: CGRect = .zero
    
        override func layoutSubviews() {
            super.layoutSubviews()
    
            // Prevent layout loop
            if previousBounds != bounds {
                previousBounds = bounds
                updateTrackImages()
            }
        }
    }
    

    @LuizfernandoSalvatera问题是什么?@matt its使缩略图(圆形图像)后面的视图在缩略图移动时透明,就像本机相机一样app@LuizFernandoSalvaterra我从来没有注意到。我的猜测是拇指只是一个透明的图像,就像最初的问题(第一个屏幕截图)一样。然后,技巧在于对可调整大小的
    minimumTrackImage
    maximumTrackImage
    进行切片。前者的右端和后者的左端是透明的,大小固定——正好是拇指圆直径的一半。@matt切片不起作用,因为最大轨迹图像会延长轨迹的长度。@AllenHumphreys是的,我发现了。只是要注意一下(一开始我也被这个问题弄糊涂了)OP想要一个穿过轨迹的透明拇指(想象一个视频在背景中全屏播放-就像照相机应用程序中的缩放滑块一样-你应该能够看到拇指内的动态内容)而且不仅仅是一个静态图像,通过与背景匹配产生透明的错觉…@Alladinian,我明白了。我想这取决于滑块后面的最终背景。假设发布的示例是灰色纹理背景,那么问题就不那么严重了。然而,如果有照片/视频等,那么我的回答也会失败。在这种情况下,他们似乎需要一个定制的滑块。我想说的是,(a)你在这一个上多走了一英里,(b)你应该得到赏金。