如何在先前转换的 UIView 上正确地动画转换
How to correctly animate transformations on an priorly transformed UIView
问题总结
无法在已翻译的 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
}
}
目前尝试次数
我已尝试将我的代码修改为 return 转换,该转换考虑了 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)
}
}
此代码未产生预期效果:视图跳到新位置,正确缩放并移动"randomly".
我肯定遗漏了一些东西——我可能瞄准了错误的最终结果矩阵——但总的来说,我目前被困住了。
是否有人知道如何执行 从已翻译的 UIView 缩放和移动 UIView 这样简单的任务?我将非常感谢他们的意见!
最佳,
编辑
一张图片可以抵得上 1,000 个单词,所以当我尝试实施到目前为止已经提出的各种建议(特别是 .scaledBy(:)
方法)时会发生什么:
你可以注意到最后的转换是正确的,但动画不是。
您是否尝试过将当前转换分配给 属性,然后修改此复制的 属性,然后重新分配给视图?
类似于:
let originalTransform = view.transform
let scaledTransform = originalTransform.scaledBy(x: 0.2, y: 0.2)
view.transform = scaledTransform
我已经使用此方法创建了一个按钮动画,效果很好,但我不确定这是否是您要查找的内容。
首先感谢@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()
}
}
这里是动画效果:移动+缩放+缩放+恢复原状
问题总结
无法在已翻译的 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
}
}
目前尝试次数
我已尝试将我的代码修改为 return 转换,该转换考虑了 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)
}
}
此代码未产生预期效果:视图跳到新位置,正确缩放并移动"randomly".
我肯定遗漏了一些东西——我可能瞄准了错误的最终结果矩阵——但总的来说,我目前被困住了。
是否有人知道如何执行 从已翻译的 UIView 缩放和移动 UIView 这样简单的任务?我将非常感谢他们的意见!
最佳,
编辑
一张图片可以抵得上 1,000 个单词,所以当我尝试实施到目前为止已经提出的各种建议(特别是 .scaledBy(:)
方法)时会发生什么:
你可以注意到最后的转换是正确的,但动画不是。
您是否尝试过将当前转换分配给 属性,然后修改此复制的 属性,然后重新分配给视图? 类似于:
let originalTransform = view.transform
let scaledTransform = originalTransform.scaledBy(x: 0.2, y: 0.2)
view.transform = scaledTransform
我已经使用此方法创建了一个按钮动画,效果很好,但我不确定这是否是您要查找的内容。
首先感谢@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()
}
}
这里是动画效果:移动+缩放+缩放+恢复原状