如何在一定程度范围内为UIView的旋转设置动画?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在一定程度范围内为UIView的旋转设置动画?相关的知识,希望对你有一定的参考价值。

在我的应用程序中,我有一个模拟读数表盘的模拟,就像你可能在汽车仪表板或控制面板上找到的那样。运行以下代码片段以获取我的意思的示例:

svg { height: 100vh; }
#dial {
  fill: white;
  stroke: #CCCCCC;
  stroke-dasharray: 405;
  transform: rotate(135deg);
  transform-origin: center;
}
#pointer {
  fill: #FF0000;
  animation: 2s infinite alternate dialrotate;
  transform-origin: bottom center;
  animation-timing-function: ease-in-out;
}
@keyframes dialrotate {
  from {
    transform: rotate(-135deg);
  }
  to {
    transform: rotate(135deg);
  }
}
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200">
  <circle id="dial" cx="99.5" cy="100.5" r="86"/>
	<polygon id="pointer" points="100.1,25.5 98.2,100 102,100"/>
</svg>

(我在我的应用程序中没有使用SVG - 我只是使用SVG将示例放在一起,因为我主要是一个Web开发人员)

这就是我现在为表盘动画制作动画的方法:

UIView.animate(
    withDuration: 0.1,
    delay: 0.0,
    options: .curveEaseOut,
    animations: {
        self.dialPointer.transform = CGAffineTransform.init(rotationAngle: radians);
    },
    completion: nil
)

我想在两个极端(270度)之间设置指针的方向。但我不希望指针在表盘边界外的较短的90度路径上旋转;即这是错误的:

svg { height: 100vh; }
#dial {
  fill: white;
  stroke: #CCCCCC;
  stroke-dasharray: 405;
  transform: rotate(135deg);
  transform-origin: center;
}
#pointer {
  fill: #FF0000;
  animation: 2s infinite alternate dialrotate;
  transform-origin: bottom center;
  animation-timing-function: ease-in-out;
}
@keyframes dialrotate {
  from {
    transform: rotate(225deg);
  }
  to {
    transform: rotate(135deg);
  }
}
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200">
  <circle id="dial" cx="99.5" cy="100.5" r="86"/>
  <polygon id="pointer" points="100.1,25.5 98.2,100 102,100"/>
</svg>

如何强制UIView旋转长距离旋转,而不是在最短的方向上旋转?

答案

正如您所发现的,默认情况下,UIView动画在插入角度值时采用最短路径。你有几个选择:

  1. 您可以将动画分解为几个较短的步骤,或者将其设置为关键帧。
  2. 您可以改为使用CABasicAnimation,并使用累积动画为图层的变换设置动画

游乐场示例:

import PlaygroundSupport
import UIKit

let rect = CGRect(x: 0, y: 0, width: 300, height: 300)
let view = UIView(frame: rect)
let bar = UIView(frame: rect.insetBy(dx: 40, dy: 140))
bar.backgroundColor = .red
view.addSubview(bar)

let animation = CABasicAnimation(keyPath: "transform.rotation.z")
animation.toValue = 1.25 * CGFloat.pi
animation.isCumulative = true
animation.duration = 5
bar.layer.add(animation, forKey: "spin")
bar.layer.transform = CATransform3DMakeRotation(1.25 * CGFloat.pi, 0, 0, 1)
PlaygroundPage.current.liveView = view
另一答案

你可以这样做

UIView.animate(
    withDuration: 0.1,
    delay: 0.0,
    options: .curveEaseOut,
    animations: {
        if radians > CGFloat.pi {
            self.dialPointer.transform = CGAffineTransform.init(rotationAngle: CGFloat.pi);
        }
        self.dialPointer.transform = CGAffineTransform.init(rotationAngle: radians);
    },
    completion: nil
)

以上是关于如何在一定程度范围内为UIView的旋转设置动画?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Swift 中多次为 UIView 的翻转设置动画

应该如何在动画中旋转UIView呢?

动画块中 UIView 的旋转和设置中心有时不起作用

顺序 UIView 转换

如何旋转 UIView?

使用核心动画和块旋转 UIView 对象的问题