Max*_*Sim 3 objective-c uikit uislider ios
如何设置清晰的拇指背景UISlider以使轨道在拇指后面不可见?
当我使用setThumbImage:forState:并传递部分透明图像时,滑块的最小轨道和最大轨道图像/颜色在拇指图像后面可见:
我希望它看起来像在 iOS 相机应用程序中,其中“透明”拇指图像圆圈剪辑轨道背景颜色:
简而言之,没有简单的 API 可以UISlider重现这种行为。
前提条件:根据问题,我只是演示如何使拇指显示透明而不显示轨道。我并不是试图准确地重新创建相机的滑块。
理想的解决方案是创建最小和最大轨道图像,利用上限插入来防止轨道的一部分被填充。我说这是理想的,因为它很简单并且相对性能较高。不幸的是,UISlider有两件事阻止了我们使用这个方法。
最大轨道图像实际上与整个轨道的宽度相同,但它包含在已clipsToBounds设置为 true 的视图中。最大轨道的超级视图已调整大小并剪辑最大轨道,以确保它在拇指的前侧永远不可见。
禁用clipsToBounds整个层次结构可以让我们在视图调试器中看到这一点。
最小轨道的大小UIImageView已调整,但当调用时,setMinimumTrackImage它UISlider实际上会创建一个不同的可调整大小的图像。这个问题需要一段时间才能弄清楚,但可以通过检查内存地址来证明。
根据我从初步调查中学到的知识,我们可以随着值的变化生成图像。这不是最有效的方法,因为它需要一遍又一遍地创建许多图像。但是,它符合原始问题的参数。请注意,您只能使用“连续”滑块有效地做到这一点,因为它依赖于值更新。从好的方面来说,这可以很容易地扩展以绘制更有趣的轨道图像(就像相机中的图像)。
这是结果,我把拇指做得很大,这样你就可以很容易地看到它是透明的。
这是课程:
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()
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2221 次 |
| 最近记录: |