【问题标题】:Animate UISlider's buffer track change?动画 UISlider 的缓冲轨道变化?
【发布时间】:2019-06-02 12:14:46
【问题描述】:

根据在线文章并使用 github 项目,我能够创建带有第二个轨道 (bufferTrack) 的 UISlider

我面临的唯一问题是更新 burrerEndValue / value。它不是动画的。如何在 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)
    }
}

【问题讨论】:

    标签: ios swift animation uibezierpath


    【解决方案1】:

    当您在draw(rect:) 函数中为UIView 实例实现自定义绘图时,您无法为它设置动画,因为在动画期间self.layer.presentationLayer 必须使用oldValuenewValue 之间的插值绘制,但是您的被覆盖的绘图逻辑总是使用新设置的值newValue

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

    为此,您可以参考this article

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

    【讨论】:

    • 感谢您抽出宝贵的时间,您真的帮了我大忙!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-08
    • 1970-01-01
    • 2022-01-16
    • 2011-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多