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

时间:2017-12-22 05:21:11

标签: ios swift uiview uiviewanimation

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

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的旋转长时间旋转,而不是在最短的方向上旋转?

2 个答案:

答案 0 :(得分:1)

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

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

    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
    

答案 1 :(得分:0)

你可以这样做

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
)