【问题标题】:How to correctly animate transformations on an priorly transformed UIView如何在先前转换的 UIView 上正确地为转换设置动画
【发布时间】:2019-02-28 22:46:52
【问题描述】:

问题摘要

无法在已翻译的UIView 上正确执行移动和缩放动画。

当视图没有事先移动时,为了达到预期的效果,我先应用缩放,然后应用平移。我使用UIViewPropertyAnimator 为生成的转换设置动画:视图在相应移动的同时放大或缩小。

但是,如果在应用此动画转换之前视图已从其原始位置移动(翻译),我未能实现在将视图从其新位置移动时放大或缩小的结果.

¡虽然转换问题有据可查 - 而且我在提交问题之前已经尽职尽责 - 到目前为止我还没有找到成功的解决方案 p>

变形动画代码

为了便于理解和解决问题,对代码进行了简化。

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 这样简单的任务,我将非常感谢他们的意见!

最好的,


编辑

一张图片可以抵 1000 个字,所以当我尝试实施迄今为止所提出的各种建议时会发生什么(特别是 .scaledBy(:) 方法):

你可以注意到最终的转换是正确的,但动画不是。

【问题讨论】:

    标签: ios swift animation transform cgaffinetransform


    【解决方案1】:

    您是否尝试过将当前转换分配给一个属性,然后修改这个复制的属性,然后重新分配给视图? 类似:

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

    我使用这种方法创建了一个按钮动画,效果很好,但我不确定它是否是您要找的。​​p>

    【讨论】:

    • 感谢@gmogames!我已经上传了一个 gif 来更好地展示这个问题。最终的转换适合您的解决方案,但动画不适合。
    • @Chris 出于好奇,如果在第二次运行(出现故障的那个)你只做缩放,或者只做翻译X,它会出现故障吗?还是只有在结合这些时才会发生故障?
    • 我两者都做,但为了调试,我只尝试了翻译和缩放。应用比例时会出现问题。
    • @Chris 我能想到的是,一个比例固定在视图中心。所以你提供的动画的最终比例实际上是小方块所在的中心。也许您需要在再次缩放之前更新图层的锚点。
    • 您也可以尝试使用 UIView.animate() 模式而不是 UIViewPropertyAnimator。我记得在hackingwithswift.com/read/15/4/transform-cgaffinetransform 上有一个很好的简单教程
    【解决方案2】:

    首先,感谢@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 + scale + scale + revert to original

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-01-28
      • 2013-11-13
      • 1970-01-01
      • 2019-07-25
      • 2019-10-06
      • 2021-11-25
      • 1970-01-01
      相关资源
      最近更新 更多