Как правильно анимировать преобразования в ранее преобразованном UIView

Краткое описание проблемы

Невозможно правильно выполнить анимацию перемещения и масштабирования для уже переведенного UIView.

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

Однако, если представление было перемещено (переведено) из его исходного положения до применения этого анимированного преобразования, мне не удалось достичь результата, состоящего в увеличении или уменьшении, в то время как перемещение представления из его новой позиции [тысяча сто тридцать два].

¡ Хотя проблемы с трансформацией хорошо задокументированы - и я провел тщательную проверку перед тем, как задавать вопрос, - мне пока не удалось найти успешного решения !

[ 1112] Код анимации преобразования

Для облегчения понимания и разрешения проблемы коды были упрощены.

extension UIView {

   func zoomAndMove(vector: CGPoint, scale: CGPoint){
      self.transform = self.transform.concatenating(CGAffineTransform(scaleX: scale.x, y: scale.y).concatenating(CGAffineTransform(translationX: vector.x, y: vector.y))
   }


   func animateZoomAndMove(from origin: CGPoint, for duration: TimeInterval, cameraZoom: CGPoint, timingFunction: UITimingCurveProvider, controlPoint2: CGPoint(x: 0.8, y: 0.7)) autoplay: Bool = false) -> UIViewPropertyAnimator {
      let animator = UIViewPropertyAnimator(duration: duration, timingParameters: timingFunction)
      let vector = CGPoint(x: self.frame.midX - origin.x, y: self.frame.midY - origin.y)

      animator.addAnimations {
         self.zoomAndMove(vector: vector, scale: cameraZoom)
      }

      if autoplay { animator.startAnimation()}
      return animator
   }
}

Попытки пока

Я попытался изменить свой код, чтобы он возвращал преобразование, которое учитывает предыдущий перевод до того, как произойдет zoomAndMove:

extension UIView {

   func zoomAndMove(vector: CGPoint, scale: CGPoint){

      if self.transform == CGAffineTransform.identity {
          self.transform = self.transform.concatenating(CGAffineTransform(scaleX: scale.x, y: scale.y).concatenating(CGAffineTransform(translationX: vector.x, y: vector.y)) 
      } else {
          let preTransform = self.transform
          self.transform = CGAffineTransform(a: scale.x, b: 0, c: 0, d: scale.y, tx: vector.x + preTransform.tx, ty: vector.y + preTransform.ty)
      }
   }

Это код не приводит к желаемому эффекту : вид переходит в новое место, корректно масштабируется и перемещается «случайным образом».

Я определенно что-то упускаю - возможно, я нацеливаюсь на неверную матрицу конечных результатов - но в целом я сейчас застрял.

Если у кого-нибудь есть подсказка о том, как выполнить такую ​​простую задачу, как масштабирование и перемещение UIView из уже переведенного UIView , я был бы очень признателен за их input!

Best,


EDIT

Изображение может стоить 1000 слов, поэтому вот что происходит, когда я пытаюсь реализовать различные предложения, которые имеют До сих пор любезно сделано (в частности, метод .scaledBy(:)):

enter image description here

Вы можете заметить, что окончательное преобразование верно, но анимации нет.

2
задан Chris 1 March 2019 в 08:54
поделиться

2 ответа

Вы пытались присвоить текущее преобразование свойству, затем изменили это скопированное свойство и затем переназначили представление? что-то вроде:

let originalTransform = view.transform
let scaledTransform = originalTransform.scaledBy(x: 0.2, y: 0.2)
view.transform = scaledTransform

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

0
ответ дан gmogames 1 March 2019 в 08:54
поделиться

Прежде всего, спасибо @gmogames, что нашли время, чтобы предложить свои предложения. Всегда полезно иметь возможность обмениваться идеями !!!

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

extension UIView {
    func scaleView(scaleFactor: CGPoint, duration: TimeInterval) {
        // store the view original center
        let oCenter = self.center

        // get the current transformation
        let cTransform = self.transform

        // set the new center of the view 
        self.center = CGPoint(x: self.frame.midX, y: self.frame.midY)

        // clears the transform matrix from potential prior translation
        // Note that you need to take into account potential prior scale of the view into the translation vector!!
        self.transform = self.transform.translatedBy(x: -cTransform.tx / cTransform.a, y: -cTransform.ty / cTransform.d)


        // Animates the transformation
        let animator = UIViewPropertyAnimator(duration: duration, timingParameters: UICubicTimingParameters(controlPoint1: CGPoint(x: 0, y: 0), controlPoint2: CGPoint(x: 1, y: 1))
        animator.addAnimations {
            self.transform = self.transform.scaledBy(x: scaleFactor.x, y: scaleFactor.y)
        }
        // resets the View to its original center and apply the transformation so that the view stays in the right end position
        animator.addCompletion { (position) in
            if position == UIViewAnimatingPosition.end {
                self.center = oCenter
                self.transform = cTransform.scaledBy(x: scaleFactor.x, y: scaleFactor.y)
            }
        }
        animator.startAnimation()
    }
}

Вот результат анимации: move + шкала + шкала + вернуться к оригиналу

enter image description here

0
ответ дан Chris 1 March 2019 в 08:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: