Круговой BezierPath заполняет слишком много по сравнению с заданным значением прогресса - iOS Swift

У меня есть круговой UIBezierPath и 2x CAShapeLayers, которые я использую для отображения прогресса в достижении определенной вехи в одном из моих приложений.

Проблема: когда я анимирую прогресс с помощью CABasicAnimation, прогресс выходит за рамки того, что он должен делать.

Контекст: я показываю этот круговой вид в подпредставлении настраиваемой ячейки внутри своего вида milestonesCollectionView.

Иерархия представления: CollectionView> Custom Cell> subview> drawRect, чтобы создать и добавить туда слои.

Мой код:

Пользовательская ячейка

Внутри моей пользовательской ячейки я настраиваю currentProgress (на данный момент жестко запрограммирован для целей тестирования)

let placeHolderForProgressView: CircularTrackerView = {
        let ctv = CircularTrackerView()
        ctv.backgroundColor = UIColor.clear
        ctv.translatesAutoresizingMaskIntoConstraints = false
        ctv.currentProgress = 0.5  //set to 0.5 to get a circle filled at 50%
        return ctv
    }()

Внутри CircularTrackerView

// Я анимирую прогресс всякий раз, когда ячейка установлена, и предоставляю currentProgress для progressView

var currentProgress: CGFloat = 0.0 {
        didSet {
            animate(to: currentProgress)
            let percent = Int(currentProgress * 100)
            percentLbl.text = "\(percent)%"
        }
    } 


let shapeLayer = CAShapeLayer() //displays the progress 
let trackLayer = CAShapeLayer() //background of the ring

override func draw(_ rect: CGRect) {
    super.draw(rect)

    let center = CGPoint(x: frame.size.width / 2, y: frame.size.height / 2)
    let circularPath = UIBezierPath(arcCenter: center, radius: frame.size.width / 2, startAngle: -CGFloat.pi / 2, endAngle: 2 * CGFloat.pi, clockwise: true)

    trackLayer.path = circularPath.cgPath
    trackLayer.strokeColor = UIColor.white.withAlphaComponent(0.2).cgColor
    trackLayer.lineWidth = 5
    trackLayer.fillColor = UIColor.clear.cgColor
    trackLayer.lineCap = kCALineCapRound
    layer.addSublayer(trackLayer)

    shapeLayer.path = circularPath.cgPath
    shapeLayer.strokeColor = UIColor.white.cgColor
    shapeLayer.lineWidth = 5
    shapeLayer.strokeEnd = 0
    shapeLayer.fillColor = UIColor.clear.cgColor
    shapeLayer.lineCap = kCALineCapRound
    layer.addSublayer(shapeLayer)

}

private func animate(to progress: CGFloat) {

    let animation = CABasicAnimation(keyPath: "strokeEnd")
    animation.fromValue = 0.0
    animation.toValue = progress
    animation.duration = 2
    animation.fillMode = kCAFillModeForwards
    animation.isRemovedOnCompletion = false

    shapeLayer.add(animation, forKey: "randomString")

}

Вывод

Круг выходит за отметку 50% ... даже сложно, я думаю, что выполнил правильные шаги, чтобы создать это (немного адаптировано из учебника LetsBuildThatApp на YouTube: https://www.youtube.com/watch?v=O3ltwjDJaMk)

введите здесь описание изображения

Заранее спасибо, если вы можете внести свой вклад, который может помочь.


person Edouard Barbier    schedule 18.02.2018    source источник


Ответы (1)


Проблема в вашем UIBezierPath / ракурсе, который вы ему даете:

let circularPath = UIBezierPath(arcCenter: center, radius: frame.size.width / 2, startAngle: -CGFloat.pi / 2, endAngle: 2 * CGFloat.pi, clockwise: true)

Разница endAngle - startAngle равна 2.5 * PI, но должна быть только 2 * PI. Когда он 2.5 * PI, это означает, что ваш strokeEnd из 0.5 приводит к 1.25 * PI, чтобы его погладили.

Решение: уменьшите endAngle на 0.5 * PI:

let circularPath = UIBezierPath(arcCenter: center, radius: frame.size.width / 2, startAngle: -0.5 * CGFloat.pi, endAngle: 1.5 * CGFloat.pi, clockwise: true)
person luk2302    schedule 18.02.2018
comment
Чувак! Большое спасибо за такой быстрый ответ! Теперь это кажется очевидным ... потрясающе! Это сработало отлично. - person Edouard Barbier; 18.02.2018
comment
@EdouardBarbier, пожалуйста, продолжайте создавать красивые интерфейсы :) - person luk2302; 19.02.2018
comment
Я обязательно буду! Выглядит намного лучше уже сейчас, когда все правильно выровнено! Спасибо еще раз ;) - person Edouard Barbier; 19.02.2018