J'ai une vue d'image sous-classée dans laquelle j'aimerais fondre, agrandir et faire pivoter, puis continuer à tourner tout en diminuant et en disparaissant.

J'utilise un bloc d'animation UIView avec un gestionnaire d'achèvement pour gérer le rétrécissement.

Le problème est que ce n'est pas une animation fluide. Avant l'exécution du gestionnaire d'achèvement, l'animation s'arrête avant de s'exécuter à nouveau. J'ai besoin que ce soit un joli "coup" d'une animation.

Code ci-dessous:

    let duration: TimeInterval = 3.0
    let rotate = CGAffineTransform(rotationAngle: CGFloat(Double.pi))


    UIView.animate(withDuration: duration * 3, delay: 0, options: [.curveLinear], animations: {
        // initial transform
        self.alpha = 0
        self.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)
        // initial spin for duration of animaton
        UIView.animate(withDuration: duration * 3, delay: 0.0, options: [.curveLinear], animations: {
            self.transform = rotate
        }, completion: nil)

        // scaling and fading
        UIView.animate(withDuration: duration, delay: 0, options: [.curveLinear], animations: {
            UIView.setAnimationRepeatCount(3)
            self.transform = self.transform.scaledBy(x: 0.8, y: 0.8)
            self.alpha = 1
        }) { (true) in
            UIView.animate(withDuration: duration, animations: {
                UIView.setAnimationRepeatCount(3)
                self.transform = self.transform.scaledBy(x: 0.1, y: 0.1)
                self.alpha = 0
            })
        }
    }, completion: nil)

Comment puis-je faire tourner l’animation tout le temps tout en s’affichant en fondu et en augmentant l’échelle avant de la réduire et de s’évanouir? L'animation entière doit durer 3 secondes et se répéter 3 fois. Merci.

2
Joe 4 mai 2017 à 22:22

3 réponses

Meilleure réponse

Pour votre demande modifiée, je développe ce que vous avez déjà vu en utilisant les animations de bloc. Comme certains l'ont dit, les animations d'images clés peuvent être meilleures, peu importe, voici la pensée.

Créez une animation qui tourne tout le temps en transformant la vue. Créez une autre animation qui effectue la mise à l'échelle et le fondu en fonction de la transformation actuelle (qui tourne). Dans cette passe, je viens de créer une variable pour vous permettre de personnaliser (et de répéter) des parties de l'animation. J'ai éclaté certaines choses pour être clair et savoir que je pourrais refactoriser pour écrire des choses encore plus concises.

Voici le code

import UIKit

class OrangeView: UIView {



override func layoutSubviews() {
    super.layoutSubviews()

  let duration: TimeInterval = 9.0

  self.transform = CGAffineTransform.identity

  // initial transform
  self.alpha = 1
  self.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)

  // start rotation
  rotate(duration: duration)

  // scaling and fading
  scaleUpAndDown(desiredRepetitions: 3, initalDuration: duration)


  }

func rotate(duration: TimeInterval) {
                UIView.animate(withDuration: duration/2.0,
                               delay: 0.0,
                               options: [.curveLinear], animations: {
                                let angle = Double.pi
                                self.transform = self.transform.rotated(by: CGFloat(angle))
                }, completion: {[weak self] finished in
  guard let strongSelf = self else {
    return
  }
  if finished &&
    strongSelf.transform != CGAffineTransform.identity {
    strongSelf.rotate(duration: duration)
  } else {
    // rotation ending
  }
})

  }

func scaleUpAndDown(timesRepeated: Int = 0, desiredRepetitions: Int, initalDuration: TimeInterval) {

guard timesRepeated < desiredRepetitions,
  desiredRepetitions > 0, initalDuration > 0 else {
  self.transform = CGAffineTransform.identity
    return
}
let repeatedCount = timesRepeated + 1

let scalingDuration = initalDuration/2.0/Double(desiredRepetitions)

UIView.animate(withDuration: scalingDuration,
               delay: 0.0,
               animations: {
                let desiredOriginalScale: CGFloat = 0.8

                let scaleX = abs(CGAffineTransform.identity.a / self.transform.a) * desiredOriginalScale
                let scaleY = abs(CGAffineTransform.identity.d / self.transform.d) * desiredOriginalScale

                self.transform = self.transform.scaledBy(x: scaleX, y: scaleY)
                self.alpha = 1
              }) { (true) in
                UIView.animate(withDuration:scalingDuration,
                               delay: 0.0,
                               animations: {

                                let desiredOriginalScale: CGFloat = 0.1

                                let scaleX = abs(CGAffineTransform.identity.a / self.transform.a) * desiredOriginalScale
                                let scaleY = abs(CGAffineTransform.identity.d / self.transform.d) * desiredOriginalScale
                                  self.transform = self.transform.scaledBy(x: scaleX, y: scaleY)
                                  self.alpha = 0
                }) { finshed in
                  self.scaleUpAndDown(timesRepeated: repeatedCount, desiredRepetitions: desiredRepetitions, initalDuration: initalDuration);
                }
              }

  }

}

Enfin voici un autre gif animé

enter image description here

4
DannyJi 5 mai 2017 à 19:05

enter image description here

Je vois le léger bégaiement en rotation au début du onCompletion.

J'ai créé une réduction avec votre code (illustré ci-dessous dans la vue bleue) et une variante dans la vue orange. Cela a été extrait du simulateur et transformé en GIF animé, donc la vitesse est ralentie. La vue orange continue de tourner alors que la transformation complète se réduit.

Ceci est le code de layoutSubviews () pour Orange View

Remplacer func layoutSubviews () {super.layoutSubviews ()

let duration: TimeInterval = 3.0
let rotate = CGAffineTransform(rotationAngle: CGFloat(Double.pi))

// initial transform
self.alpha = 0
self.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)

// initial spin for duration of animaton
UIView.animate(withDuration: duration,
               delay: 0.0,
               options: [.curveLinear],
               animations: {
                  self.transform = rotate;
                },
               completion: nil)
// scaling and fading
UIView.animate(withDuration: duration/2.0, animations: {
  self.transform = self.transform.scaledBy(x: 0.8, y: 0.8)
  self.alpha = 1
}) { (true) in
  UIView.animate(withDuration: duration/2.0, animations: {
    self.transform = self.transform.scaledBy(x: 0.1, y: 0.1)
    self.alpha = 0
  })
}

}

3
DannyJi 4 mai 2017 à 20:43

Essayez d'utiliser CGAffineTransformConcat ()

  CGAffineTransform scale = CGAffineTransformMakeScale(0.8, 0.8);
  self.transform = CGAffineTransformConcat(CGAffineTransformRotate(self.transform, M_PI / 2), scale);
1
whyp 4 mai 2017 à 19:37