одушевленный CAShapeLayer на круговой дорожке - PullRequest
0 голосов
/ 18 октября 2018

Я хочу анимировать слой с большим пальцем на нарисованной траектории.Я могу анимировать слой прогресса согласно значению, но перемещение всего слоя не работает.

enter image description here

func setProgress(_ value:Double, _ animated :Bool) {
    let progressAnimation = CABasicAnimation(keyPath: "strokeEnd")
    progressAnimation.duration = animated ? 0.6 : 0.0
    progressAnimation.fromValue = currentValue
    progressAnimation.toValue = value
    progressAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
    progressLayer.strokeEnd = CGFloat(value)
    progressLayer.add(progressAnimation, forKey: "animateprogress")
}

Используя эту функцию, я могуоживить слой прогресса.и я застрял в положении анимации большого пальца.

Я пробовал некоторые вещи, но это не работает.

неудачная попытка 1

    guard let path = thumbLayer.path else {return}
    let center = CGPoint(x: frame.width/2, y: frame.height/2)
    let radius = min(frame.width, frame.height)/2 - max(trackWidth, max(progressWidth, thumbWidth))/2
    let thumbAngle = 2 * .pi * currentValue - (.pi/2)
    let thumbX = CGFloat(cos(thumbAngle)) * radius
    let thumbY = CGFloat(sin(thumbAngle)) * radius
    let newThumbCenter = CGPoint(x: center.x + thumbX, y: center.y + thumbY)
    let thumbPath = UIBezierPath(arcCenter: newThumbCenter, radius: thumbWidth/2, startAngle: -.pi/2, endAngle: .pi*1.5, clockwise: true)

    let thumbAnimation = CABasicAnimation(keyPath: "path")
    thumbAnimation.duration = animated ? 0.6 : 0.0
    thumbAnimation.fromValue = path
    thumbAnimation.toValue = thumbPath.cgPath
    thumbAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
    thumbLayer.strokeEnd = CGFloat(value)
    thumbLayer.add(thumbAnimation, forKey: "animateprogress")

неудачная попытка 2

    let intialPosition = thumbLayer.position
    let center = CGPoint(x: frame.width/2, y: frame.height/2)
    let radius = min(frame.width, frame.height)/2 - max(trackWidth, max(progressWidth, thumbWidth))/2
    let thumbAngle = 2 * .pi * currentValue - (.pi/2)
    let thumbX = CGFloat(cos(thumbAngle)) * radius
    let thumbY = CGFloat(sin(thumbAngle)) * radius
    let newThumbCenter = CGPoint(x: center.x + thumbX - thumbCenter.x, y: center.y + thumbY - thumbCenter.y)

    thumbLayer.position.x = newThumbCenter.x
    let thumbAnimationX = CABasicAnimation(keyPath: "progress.x")
    thumbAnimationX.duration = animated ? 0.6 : 0.0
    thumbAnimationX.fromValue = intialPosition.x
    thumbAnimationX.toValue = newThumbCenter.x
    thumbAnimationX.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
    thumbLayer.add(thumbAnimationX, forKey: "progress.x")


    thumbLayer.position.y = newThumbCenter.y
    let thumbAnimationY = CABasicAnimation(keyPath: "progress.y")
    thumbAnimationY.duration = animated ? 0.6 : 0.0
    thumbAnimationY.fromValue = intialPosition.y
    thumbAnimationY.toValue = newThumbCenter.y
    thumbAnimationY.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
    thumbLayer.add(thumbAnimationY, forKey: "progress.y")

1 Ответ

0 голосов
/ 18 октября 2018

В первой попытке вы пытаетесь анимировать путь большого пальца (контур красного круга).Во второй попытке вы пытаетесь анимировать position из thumbLayer (но вы анимировали неверные ключевые пути).

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

Swiss railway clock

В частности, посмотрите на красную точку в конце второгорука.Как часы перемещают эту красную точку вокруг лица?Вращая секундную стрелку вокруг центра лица.

Это то, что мы собираемся сделать, но мы не будем рисовать всю секундную стрелку.Мы просто нарисуем красную точку в конце.

Мы поместим начало координатной системы thumbLayer в центр круговой дорожки, и мы установим ее путь так, чтобыбольшой палец появляется на пути.Вот макет:

layout

Вот код для установки circleLayer и thumbLayer:

    private let circleLayer = CAShapeLayer()
    private let thumbLayer = CAShapeLayer()

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        let circleRadius: CGFloat = 100
        let thumbRadius: CGFloat = 22
        let circleCenter = CGPoint(x: view.bounds.midX, y: view.bounds.midY)

        circleLayer.fillColor = nil
        circleLayer.strokeColor = UIColor.black.cgColor
        circleLayer.lineWidth = 4
        circleLayer.lineJoin = .round
        circleLayer.path = CGPath(ellipseIn: CGRect(x: -circleRadius, y: -circleRadius, width: 2 * circleRadius, height: 2 * circleRadius), transform: nil)
        circleLayer.position = circleCenter
        view.layer.addSublayer(circleLayer)

        thumbLayer.fillColor = UIColor.red.cgColor
        thumbLayer.strokeColor = nil
        thumbLayer.path = CGPath(ellipseIn: CGRect(x: -thumbRadius, y: -circleRadius - thumbRadius, width: 2 * thumbRadius, height: 2 * thumbRadius), transform: nil)
        thumbLayer.position = circleCenter
        view.layer.addSublayer(thumbLayer)
    }

СПри такой компоновке мы можем перемещать большой палец вдоль дорожки, не меняя ее положения.Вместо этого мы вращаем thumbLayer вокруг его источника:

    @IBAction func buttonWasTapped() {
        let animation = CABasicAnimation(keyPath: "transform.rotation")
        animation.fromValue = 0
        animation.toValue = 2 * CGFloat.pi
        animation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
        animation.duration = 1.5
        animation.isAdditive = true
        thumbLayer.add(animation, forKey: nil)
    }

Результат:

demo

...