跟随在线文章并使用github项目,我能够创建带有第二条轨道( bufferTrack )的UISlider
。
我面临的唯一问题是更新 burrerEndValue / 值。它没有动画。如何在UIBezierPath上实现平滑的动画?
open class BufferSlider: UISlider {
open var bufferStartValue:Double = 0 {
didSet{
if bufferStartValue < 0.0 {
bufferStartValue = 0
}
if bufferStartValue > bufferEndValue {
bufferStartValue = bufferEndValue
}
self.setNeedsDisplay()
}
}
open var bufferEndValue:Double = 0 {
didSet{
if bufferEndValue > 1.0 {
bufferEndValue = 1
}
if bufferEndValue < bufferStartValue{
bufferEndValue = bufferStartValue
}
self.setNeedsDisplay()
}
}
open var baseColor:UIColor = UIColor.white
open var progressColor:UIColor?
open var bufferColor:UIColor?
open var customBorderWidth: Double = 0.1{
didSet{
if customBorderWidth < 0.1 {
customBorderWidth = 0.1
}
self.setNeedsDisplay()
}
}
open var sliderHeight: Double = 6 {
didSet{
if sliderHeight < 1 {
sliderHeight = 1
}
}
}
override open func setValue(_ value: Float, animated: Bool) {
super.setValue(value, animated: animated)
self.setNeedsDisplay()
}
override init(frame: CGRect) {
super.init(frame: frame)
updateView()
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
updateView()
}
func updateView() {
baseColor = UIColor.white
progressColor = appColors.red
bufferColor = appColors.fadedRed
}
open override func trackRect(forBounds bounds: CGRect) -> CGRect {
var result = super.trackRect(forBounds: bounds)
result.size.height = 0.01
return result
}
open override func draw(_ rect: CGRect) {
baseColor.set()
let rect = self.bounds.insetBy(dx: CGFloat(customBorderWidth), dy: CGFloat(customBorderWidth))
let height = sliderHeight.CGFloatValue
let radius = height/2
let sliderRect = CGRect(x: rect.origin.x, y: rect.origin.y + (rect.height/2-radius), width: rect.width, height: rect.width) //default center
let path = UIBezierPath()
path.addArc(withCenter: CGPoint(x: sliderRect.minX + radius, y: sliderRect.minY+radius), radius: radius, startAngle: CGFloat(Double.pi)/2, endAngle: -CGFloat(Double.pi)/2, clockwise: true)
path.addLine(to: CGPoint(x: sliderRect.maxX-radius, y: sliderRect.minY))
path.addArc(withCenter: CGPoint(x: sliderRect.maxX-radius, y: sliderRect.minY+radius), radius: radius, startAngle: -CGFloat(Double.pi)/2, endAngle: CGFloat(Double.pi)/2, clockwise: true)
path.addLine(to: CGPoint(x: sliderRect.minX + radius, y: sliderRect.minY+height))
baseColor.setStroke()
path.lineWidth = customBorderWidth.CGFloatValue
path.stroke()
path.fill()
path.addClip()
var fillHeight = sliderRect.size.height-customBorderWidth.CGFloatValue
if fillHeight < 0 {
fillHeight = 0
}
let fillRect = CGRect(
x: sliderRect.origin.x + sliderRect.size.width*CGFloat(bufferStartValue),
y: sliderRect.origin.y + customBorderWidth.CGFloatValue/2,
width: sliderRect.size.width*CGFloat(bufferEndValue-bufferStartValue),
height: fillHeight)
if let color = bufferColor { color.setFill() }
else if let color = self.superview?.tintColor{ color.setFill()}
else{ UIColor(red: 0.0, green: 122.0/255.0, blue: 1.0, alpha: 1.0).setFill() }
UIBezierPath(rect: fillRect).fill()
if let color = progressColor{
color.setFill()
let fillRect = CGRect(
x: sliderRect.origin.x,
y: sliderRect.origin.y + customBorderWidth.CGFloatValue/2,
width: sliderRect.size.width*CGFloat((value-minimumValue)/(maximumValue-minimumValue)),
height: fillHeight)
UIBezierPath(rect: fillRect).fill()
}
}
}
extension Double{
var CGFloatValue: CGFloat {
return CGFloat(self)
}
}
答案 0 :(得分:1)
在UIView
函数中为其实现自定义绘图时,不能为draw(rect:)
实例设置动画,因为在动画self.layer.presentationLayer
期间必须使用{{1}之间的插值来绘制}和oldValue
,但是您绘制的覆盖逻辑始终使用新设置的值newValue
进行绘制。
您可以在newValue
实例中使用所需的动画进行自定义绘制。
考虑在CALayer
中实现绘图逻辑。
对于图层上的动画,您需要插值要设置动画的值,例如BufferSliderLayer: CALayer
和bufferEndValue
。
为此,您可以参考this article。
然后,只需将value
添加到滑块的BufferSliderLayer
初始化程序的BufferSlider
视图的图层中,并在init(frame:)
中适当调整图层大小。