Как я могу повторить анимацию (используя UIViewPropertyAnimator) определенное количество раз?

Я хочу добиться эффекта пульсации для кнопки и, следовательно, нужно несколько раз повторять эффект spring, проблема в том, что я не могу найти никакой информации о том, какие параметры предоставить и как это сделать

let btnView = sayWordBtn.viewWithTag(0)
    btnView.transform = CGAffineTransform(scaleX: 0.7, y: 0.7)
    let mass: CGFloat = 2.0 // weight of the object
        let stiffness: CGFloat = 25.0 //elasticity
        let damping: CGFloat = 2*sqrt(mass*stiffness) // point where the system comes to rest in the shortest period of time
        let underDamping: CGFloat = damping * 0.5
        let initialVelocity: CGVector = CGVector.zero
        let springParameters: UISpringTimingParameters = UISpringTimingParameters(mass: mass, stiffness: stiffness, damping: underDamping, initialVelocity: initialVelocity)
        let animationDelay = 3

        let pulseEffect = UIViewPropertyAnimator(duration: 5, timingParameters: springParameters)
        pulseEffect.addAnimations( {[weak self] in
          btnView!.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
          })
        pulseEffect.isReversed = true
        pulseEffect.startAnimation(afterDelay: TimeInterval(animationDelay))

Ответ 1

iOS 10 вводит новый объект, называемый UIViewPropertyAnimator. Вы можете сделать то же самое, что и с UIView.animation, но для достижения более сложных анимаций apple предоставляет нам CoreAnimation framework.

Почему мы должны использовать его?

Потому что UIViewPropertyAnimator - хорошо написанный и высоко расширяемый API. Он охватывает те же функции, что и анимация в стиле UIView, но дает вам тонкий программный контроль над анимацией. Это означает, что вы можете приостановить анимацию в процессе выполнения, перезапустить ее позже, если хотите, и даже динамически модифицировать анимационные свойства (например, изменить конечную точку анимации в верхнем правом углу экрана, когда она была ранее - оставил). Мы создаем его экземпляр и создаем анимацию следующим образом:

let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
view.alpha = 0.35 
view.backgroundColor = .red
self.view.addSubview(view)
let newFrame = CGRect(x: 0, y: 0, width: 50, height: 50)
let viewFrameAnimator = UIViewPropertyAnimator(duration: 1.0, 
                                                  curve: .linear, 
                                             animations: { view.frame = newFrame })

Теперь мы можем взаимодействовать с анимациями, используя:

viewFrameAnimator.startAnimation..
viewFrameAnimator.stopAnimation..
viewFrameAnimator.finishAnimation(at:..

чтобы продолжить пример выше:

viewFrameAnimator.startAnimation()

Затем, чтобы вернуться к alpha, равному 1, если нам нужно больше параметров анимации, мы также можем запустить this UIViewPropertyAnimator открытый класс:

let viewAlphaAnimator = UIViewPropertyAnimator.runningPropertyAnimator(withDuration: 1.0, 
                                                       delay: 0.0,
                                                     options: [.curveLinear],
                                                  animations: { view.alpha = 1.0 })

дайте нам добавить дополнительные опции анимации. Теперь вы знаете больше, чем этот новый объект.

Как его повторить?

Итак, давайте начнем объяснять, как повторять анимацию, например, если мы хотим повторить view.alpha = 1.0 для 3 раз (вы можете увидеть маленькую вспышку для каждого повторения для вывода.), вы должны следовать:

let viewAlphaAnimator = UIViewPropertyAnimator.runningPropertyAnimator(withDuration: 1.0,
                                                delay: 0.0,
                                                options: [.curveLinear,.repeat],
                                                animations: { UIView.setAnimationRepeatCount(3);view.alpha = 1.0 })

Надеюсь, это поможет вам.

Ответ 2

Пожалуйста, используйте

    pulseEffect.addCompletion({_ in
            // Repeat the logic here
    })

Вы можете повторить логику анимации внутри блока addCompletion

func animateView() {
    btnView.transform = CGAffineTransform(scaleX: 0.7, y: 0.7)
    let mass: CGFloat = 2.0 // weight of the object
    let stiffness: CGFloat = 25.0 //elasticity
    let damping: CGFloat = 2*sqrt(mass*stiffness) // point where the system comes to rest in the shortest period of time
    let underDamping: CGFloat = damping * 0.5
    let initialVelocity: CGVector = CGVector.zero
    let springParameters: UISpringTimingParameters = UISpringTimingParameters(mass: mass, stiffness: stiffness, damping: underDamping, initialVelocity: initialVelocity)
    let animationDelay = 3

    let pulseEffect = UIViewPropertyAnimator(duration: 5, timingParameters: springParameters)
    pulseEffect.addAnimations( {[weak self] in
        self?.btnView!.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
        })
    pulseEffect.addCompletion({_ in
        self.animateView()
    })
    pulseEffect.isReversed = true
    pulseEffect.startAnimation(afterDelay: TimeInterval(animationDelay))
}

Вы также можете добавить логику, чтобы ограничить анимацию определенным числом в блоке addCompletion

Ответ 3

Этот код работает:

func usePropertyAnimator(_ reversed: Bool = false) {

    let circleAnimator = UIViewPropertyAnimator(
        duration: 2, timingParameters: UICubicTimingParameters())

    circleAnimator.addAnimations {
        circle.center.y += (reversed ? -1 : 1) * 330
    }

    circleAnimator.addCompletion { _ in
        usePropertyAnimator(!reversed)
    }

    circleAnimator.startAnimation()

}

usePropertyAnimator()

Ответ 4

По какой-то причине они не указали возможность указать количество повторов с помощью UIPropertyAnimator. У вас останутся следующие варианты:

  • Держите счетчик и повторите анимацию в обработчике завершения и уменьшите счетчик до тех пор, пока счетчик не достигнет 0
  • Анимация с неопределенным повторением, но планирование таймера и остановка анимация (необязательно добавьте анимацию, чтобы перейти к финальной положение)
  • Отрегулируйте параметры spring, чтобы было меньше увлажнения и больше эластичности, и вы получите больше колебаний.
  • Используйте старые методы UIView.animate вместе со старым UIView.setAnimationRepeatCount
  • Использовать CASpringAnimation, поскольку это то, что аниматор Property обертывает в любом случае, и у него есть счетчик повторений.

Ответ 5

Пожалуйста, используйте этот измененный код

let btnView = sayWordBtn.viewWithTag(0)
btnView.transform = CGAffineTransform(scaleX: 0.7, y: 0.7)
let mass: CGFloat = 2.0 // weight of the object
    let stiffness: CGFloat = 25.0 //elasticity
    let damping: CGFloat = 2*sqrt(mass*stiffness) // point where the system comes to rest in the shortest period of time
    let underDamping: CGFloat = damping * 0.5
    let initialVelocity: CGVector = CGVector.zero
    let springParameters: UISpringTimingParameters = UISpringTimingParameters(mass: mass, stiffness: stiffness, damping: underDamping, initialVelocity: initialVelocity)
    let animationDelay = 3

    let pulseEffect = UIViewPropertyAnimator(duration: 5, timingParameters: springParameters)
    pulseEffect.addAnimations( {[weak self] in
        UIView.setAnimationRepeatCount(3)
        UIView.setAnimationRepeatAutoreverses(true)
        btnView!.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
      })
    pulseEffect.isReversed = true
    pulseEffect.startAnimation(afterDelay: TimeInterval(animationDelay))