繁体   English   中英

如何仅在特定角度范围内为UIView的旋转设置动画?

[英]How can I animate a UIView's rotation only within a certain degree range?

在我的应用程序中,我模拟了一个模拟读数拨盘,就像您在汽车仪表板上或控制面板上可能会看到的那样。 运行以下代码片段,以了解我的意思:

 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
)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM