UISlider не понятное поведение
День добрый, когда бегунок слайдера идет по progresBar в начале не идет закрашивание области за ним, после прохождения определенного этапа оно закрашивается. Такое же поведение и при приближении к концу, финальная область закрашивается сразу и после этого бегунок до нее доходит. Подскажите как решить проблему окраски начальной области
Код для слайдера
class CustomPlayerSlider: UISlider {
@IBInspectable var trackHeight: CGFloat = 25
@IBInspectable var thumbRadius: CGFloat = 0
private lazy var thumbView: UIView = {
let thumb = UIView()
thumb.backgroundColor = .yellow//thumbTintColor
thumb.layer.borderWidth = 0.4
thumb.layer.borderColor = UIColor.darkGray.cgColor
return thumb
}()
override func awakeFromNib() {
super.awakeFromNib()
let thumb = thumbImage(radius: thumbRadius)
setThumbImage(thumb, for: .normal)
}
private func thumbImage(radius: CGFloat) -> UIImage {
thumbView.frame = CGRect(x: 0, y: radius / 2, width: radius, height: radius)
thumbView.layer.cornerRadius = radius / 2
let renderer = UIGraphicsImageRenderer(bounds: thumbView.bounds)
return renderer.image { rendererContext in
thumbView.layer.render(in: rendererContext.cgContext)
}
}
override func trackRect(forBounds bounds: CGRect) -> CGRect {
let originalRect = super.trackRect(forBounds: bounds)
return CGRect(origin: CGPoint(x: originalRect.origin.x, y: originalRect.origin.y - (trackHeight / 2)), size: CGSize(width: bounds.width - 10, height: trackHeight))
}
}
объявление слайдера в контролере
lazy var progressSlider: CustomPlayerSlider = {
let slider = CustomPlayerSlider()
slider.minimumTrackTintColor = UIColor.rgbColorFor(hex: "#719FB0")
slider.maximumTrackTintColor = .white
slider.value = 0.0
slider.isContinuous = true
let image = UIImage(named: "thumbs")
slider.setThumbImage(image, for: .normal)
//slider.setThumbImage(nil, for: .disabled)
return slider
}()
Движение слайдера в зависимости от времени плеера
self.playRecord(index: indexPath.row) { (time, isPlaying) in
DispatchQueue.main.async {
cell.progressSlider.value = Float(time)
}
}
Ответы (1 шт):
Подтверждаю такое странное поведение слайдера при использовании свойств minimumTrackTintColor и maximumTrackTintColor и одновременном переопределении метода trackRect(forBounds:).
Например вот что выходит при использовании
maximumTrackTintColor = .red
minimumTrackTintColor = .green
// ...
override func trackRect(forBounds bounds: CGRect) -> CGRect {
let originalRect = super.trackRect(forBounds: bounds)
// woraround for left slider edge clipping
let clippingAdjustment: CGFloat = 3.0
return CGRect(origin: CGPoint(x: originalRect.origin.x - clippingAdjustment, y: originalRect.origin.y - thumbRadius / 2 ), size: CGSize(width: bounds.width, height: trackHeight))
}
Решение
использовать кастомные изображения для фона слайдера, полный пример:
class CustomPlayerSlider: UISlider {
@IBInspectable var trackHeight: CGFloat = 25
@IBInspectable var thumbRadius: CGFloat = 25 // FIXME: actially it's diameter, rename
private lazy var thumbView: UIView = {
let thumb = UIView()
thumb.backgroundColor = .yellow
thumb.layer.borderWidth = 0.4
thumb.layer.borderColor = UIColor.darkGray.cgColor
return thumb
}()
private lazy var minimumTrackView: UIView = {
let thumb = UIView()
thumb.backgroundColor = .red
return thumb
}()
private lazy var maximumTrackView: UIView = {
let thumb = UIView()
thumb.backgroundColor = .green
return thumb
}()
override func awakeFromNib() {
super.awakeFromNib()
let thumb = thumbImage(radius: thumbRadius)
setThumbImage(thumb, for: .normal)
// set custom images
setMinimumTrackImage(minimumTrackImage(size: CGSize(width: thumbRadius, height: thumbRadius)), for: .normal)
setMaximumTrackImage(maximumTrackImage(size: CGSize(width: thumbRadius, height: thumbRadius)), for: .normal)
// add rounding
layer.cornerRadius = thumbRadius / 2
layer.masksToBounds = true
}
private func thumbImage(radius: CGFloat) -> UIImage {
thumbView.frame = CGRect(x: 0, y: radius / 2, width: radius, height: radius)
thumbView.layer.cornerRadius = radius / 2
let renderer = UIGraphicsImageRenderer(bounds: thumbView.bounds)
return renderer.image { rendererContext in
thumbView.layer.render(in: rendererContext.cgContext)
}
}
private func minimumTrackImage(size: CGSize) -> UIImage {
minimumTrackView.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height)
let renderer = UIGraphicsImageRenderer(bounds: minimumTrackView.bounds)
return renderer.image { rendererContext in
minimumTrackView.layer.render(in: rendererContext.cgContext)
}
}
private func maximumTrackImage(size: CGSize) -> UIImage {
maximumTrackView.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height)
let renderer = UIGraphicsImageRenderer(bounds: maximumTrackView.bounds)
return renderer.image { rendererContext in
maximumTrackView.layer.render(in: rendererContext.cgContext)
}
}
override func trackRect(forBounds bounds: CGRect) -> CGRect {
let originalRect = super.trackRect(forBounds: bounds)
// workaround for left slider edge clipping
let clippingAdjustment: CGFloat = 3.0
return CGRect(origin: CGPoint(x: originalRect.origin.x - clippingAdjustment, y: originalRect.origin.y), size: CGSize(width: bounds.width, height: trackHeight))
}
}
Дополнение
Обрезание "хваталки" слайдера (или как ее еще обозвать?) в крайних положениях происходит скорее всего из-за того, что она выравнивается по центру относительно точки перемещения, исправить это можно, ограничивая его крайние значения, которые здесь я взял приблизительно, посмотрев на вывод значений при перемещении, при желании их вероятно можно вычислять отталкиваясь от размера слайдера и хваталки
override func thumbRect(forBounds bounds: CGRect, trackRect rect: CGRect, value: Float) -> CGRect {
print(value)
// TODO: calculate this values instead of hardcoding
let minValue: Float = 0.008
let maxValue: Float = 0.9925634
var value = value
if value < minValue {
value = minValue
} else if value > maxValue {
value = maxValue
}
return super.thumbRect(forBounds: bounds, trackRect: rect, value: value)
}



