动画UISlider的缓冲区轨迹更改?

时间:2019-06-02 12:14:46

标签: ios swift animation uibezierpath

跟随在线文章并使用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)
    }
}

1 个答案:

答案 0 :(得分:1)

UIView函数中为其实现自定义绘图时,不能为draw(rect:)实例设置动画,因为在动画self.layer.presentationLayer期间必须使用{{1}之间的插值来绘制}和oldValue,但是您绘制的覆盖逻辑始终使用新设置的值newValue进行绘制。

您可以在newValue实例中使用所需的动画进行自定义绘制。 考虑在CALayer中实现绘图逻辑。 对于图层上的动画,您需要插值要设置动画的值,例如BufferSliderLayer: CALayerbufferEndValue

为此,您可以参考this article

然后,只需将value添加到滑块的BufferSliderLayer初始化程序的BufferSlider视图的图层中,并在init(frame:)中适当调整图层大小。