Анимировать изменение буфера в UISlider? - PullRequest
2 голосов
/ 02 июня 2019

После публикации онлайн-статьи и использования проекта github я смог создать UISlider со вторым треком ( bufferTrack ).

Единственная проблема, с которой я сталкиваюсь - это обновление 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 Ответ

1 голос
/ 19 июня 2019

Вы не можете анимировать экземпляр UIView, когда вы реализовали для него пользовательское рисование в функции draw(rect:), потому что во время анимации self.layer.presentationLayer нужно рисовать с интерполированными значениями между oldValue и newValue, но вашпереопределенная логика рисования всегда рисует с новым установленным значением newValue.

. Вы можете выполнять произвольное рисование с анимациями, которые вам нужны только в экземпляре CALayer.Рассмотрите возможность реализации вашей логики рисования в BufferSliderLayer: CALayer.Для анимации на слое вам нужно будет интерполировать значения, которые вы хотите анимировать, например, bufferEndValue и value.

. Для этого вы можете обратиться к этой статье .

Затем просто добавьте BufferSliderLayer к слою BufferSlider вида в инициализаторе ползунка init(frame:) и правильно определите размер слоя в layoutSubviews.

...