Как правильно анимировать преобразования в ранее преобразованном UIView - PullRequest
0 голосов
/ 01 марта 2019

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

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

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

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

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

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

Чтобы облегчить понимание и решить проблему, коды были упрощены.

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 ]

0 голосов
/ 01 марта 2019

Прежде всего, спасибо @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 голосов
/ 01 марта 2019

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

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

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

...