ios - 动画 UISlider 的缓冲区轨道变化?

标签 ios swift animation uibezierpath

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

最佳答案

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

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

为此,您可以引用this article .

然后,只需将 BufferSliderLayer 添加到 slider 的 init(frame:) 初始化器中的 BufferSlider View 层上,并在 中适当调整层大小>布局 subview

关于ios - 动画 UISlider 的缓冲区轨道变化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56414915/

相关文章:

iphone - iOS Facebook 请求对话框不起作用

ios - 用于改进代码完成的 Xcode 插件

ios - 限制为单个小数点

swift - 如何获取字符串中的第一个字符? ( swift 3)

ios - 日期格式化程序在某些情况下返回 null(在 12 :59:59) 之后

Swift 日期时区问题

swift - 在动态 tableView 的 tableViewCell 中从动态 collectionViewCell 执行 Segue With Identifier,swift

javascript - 了解 EaselJS 的动画/物理/数学实现

java - 动画 Sprite 的问题

Android系列动画多个 subview