在 Swift 中无限期旋转 360 度视图?
Posted
技术标签:
【中文标题】在 Swift 中无限期旋转 360 度视图?【英文标题】:Rotate a view for 360 degrees indefinitely in Swift? 【发布时间】:2015-01-03 13:43:20 【问题描述】:我想将图像视图无限旋转 360 度。
UIView.animate(withDuration: 2, delay: 0, options: [.repeat], animations:
self.view.transform = CGAffineTransform(rotationAngle: 6.28318530717959)
, completion: nil)
我该怎么做?
【问题讨论】:
【参考方案1】:更新 Swift 5.x
// duration will helps to control rotation speed
private func rotateView(targetView: UIView, duration: Double = 5)
UIView.animate(withDuration: duration, delay: 0.0, options: .curveLinear, animations:
targetView.transform = targetView.transform.rotated(by: .pi)
) finished in
self.rotateView(targetView: targetView, duration: duration)
Swift 2.x 无限旋转 UIView 的方法,根据之前的答案编译:
// Rotate <targetView> indefinitely
private func rotateView(targetView: UIView, duration: Double = 1.0)
UIView.animateWithDuration(duration, delay: 0.0, options: .CurveLinear, animations:
targetView.transform = CGAffineTransformRotate(targetView.transform, CGFloat(M_PI))
) finished in
self.rotateView(targetView, duration: duration)
更新 Swift 3.x
// Rotate <targetView> indefinitely
private func rotateView(targetView: UIView, duration: Double = 1.0)
UIView.animate(withDuration: duration, delay: 0.0, options: .curveLinear, animations:
targetView.transform = targetView.transform.rotated(by: CGFloat(M_PI))
) finished in
self.rotateView(targetView: targetView, duration: duration)
【讨论】:
这不是一个流畅的动画。每次动画重复时都会有轻微的打嗝。 它停止第一个动画,并在动画完全停止后再次启动((如何强制它在动画之间无延迟地移动 @AlekseyTimoshchenko,为了让动画重新开始,您必须将其变换重置为finished
块中的标识 targetView.transform = .identity
【参考方案2】:
Swift 3.0
let imgViewRing = UIImageView(image: UIImage(named: "apple"))
imgViewRing.frame = CGRect(x: 0, y: 0, width: UIImage(named: "apple")!.size.width, height: UIImage(named: "apple")!.size.height)
imgViewRing.center = CGPoint(x: self.view.frame.size.width/2.0, y: self.view.frame.size.height/2.0)
rotateAnimation(imageView: imgViewRing)
self.view.addSubview(imgViewRing)
这是动画逻辑
func rotateAnimation(imageView:UIImageView,duration: CFTimeInterval = 2.0)
let rotateAnimation = CABasicAnimation(keyPath: "transform.rotation")
rotateAnimation.fromValue = 0.0
rotateAnimation.toValue = CGFloat(.pi * 2.0)
rotateAnimation.duration = duration
rotateAnimation.repeatCount = .greatestFiniteMagnitude
imageView.layer.add(rotateAnimation, forKey: nil)
你可以在这个link查看输出
【讨论】:
可以用CGFloat.pi代替M_PI,我觉得看起来更swifty 嗨@Mr.Xcoder 您的代码对我来说工作正常,但如果我试图在collectionview 单元格动画中应用此动画,则无法正常工作。某些单元格动画某些单元格不。【参考方案3】:使用此扩展将 UIImageView 旋转 360 度。
extension UIView
func rotate360Degrees(duration: CFTimeInterval = 1.0, completionDelegate: AnyObject? = nil)
let rotateAnimation = CABasicAnimation(keyPath: "transform.rotation")
rotateAnimation.fromValue = 0.0
rotateAnimation.toValue = CGFloat(M_PI)
rotateAnimation.duration = duration
if let delegate: CAAnimationDelegate = completionDelegate as! CAAnimationDelegate?
rotateAnimation.delegate = delegate
self.layer.addAnimation(rotateAnimation, forKey: nil)
比旋转 UIImageView 简单地使用这个方法
self.YOUR_SUBVIEW.rotate360Degrees()
【讨论】:
你能用 swift 为 NSImageView 包含这个扩展吗? 在 swift 3 中:有一个问题:无法将类型“AnyObject”的值分配给类型“CAAnimationDelegate?”修复它:用这个if let delegate: CAAnimationDelegate = completionDelegate as! CAAnimationDelegate?
切换这个if let delegate: AnyObject = completionDelegate
谢谢@HassanTaleb,这正是我要找的……愚蠢的 Swift3 u_u 破坏了我所有的应用程序!
您还需要将rotateAnimation.toValue = CGFloat(M_PI)
更改为rotateAnimation.toValue = CGFloat(M_PI * 2)
以使其移动【参考方案4】:
这个在 Swift 2.2 中对我有用:
let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
rotationAnimation.fromValue = 0.0
rotationAnimation.toValue = 360 * CGFloat(M_PI/180)
let innerAnimationDuration : CGFloat = 1.0
rotationAnimation.duration = Double(innerAnimationDuration)
rotationAnimation.repeatCount = HUGE
self.imageView.addAnimation(rotationAnimation, forKey: "rotateInner")
【讨论】:
0 * CGFloat(M_PI/180)
genius 0 次任何事情总是会导致 0。
我想这是为了说明你可以从任何角度到任何角度开始。【参考方案5】:
我会把它放在像rotateImage()
这样的函数中,然后在完成代码中再次调用rotateImage()
。不过,我认为您应该使用 M_PI(或 swift 等效项)作为旋转量。
【讨论】:
M_PI 为 180 度。但旋转 2 * M_PI 实际上不会做任何事情。但是,是的,你是对的。在一个方法中旋转 180 度,然后在完成时再次调用相同的方法。 如果您正在调用完成例程,则不需要重复选项。将UIViewAnimationOptions.Repeat
替换为UIViewAnimationOptions.CurveLinear
【参考方案6】:
为 Swift 3 更新: 我对 UIView 进行了扩展,并在其中包含以下功能:
func rotate(fromValue: CGFloat, toValue: CGFloat, duration: CFTimeInterval = 1.0, completionDelegate: Any? = nil)
let rotateAnimation = CABasicAnimation(keyPath: >"transform.rotation")
rotateAnimation.fromValue = fromValue
rotateAnimation.toValue = toValue
rotateAnimation.duration = duration
if let delegate: Any = completionDelegate
rotateAnimation.delegate = delegate as? CAAnimationDelegate
self.layer.add(rotateAnimation, forKey: nil)
然后您可以通过(例如,在我制作成按钮的 UIView 上)调用该函数:
monitorButton.rotate(fromValue: 0.0, toValue: CGFloat(M_PI * 2), completionDelegate: self)
希望这会有所帮助!
【讨论】:
【参考方案7】:我认为您在这里真正想要的是使用CADisplayLink。原因是与使用可能会导致轻微打嗝并且不容易取消的完成块相比,这将无限期顺利。请参阅以下解决方案:
var displayLink : CADisplayLink?
var targetView = UIView()
func beginRotation ()
// Setup display link
self.displayLink = CADisplayLink(target: self, selector: #selector(onFrameInterval(displayLink:)))
self.displayLink?.preferredFramesPerSecond = 60
self.displayLink?.add(to: .current, forMode: RunLoop.Mode.default)
func stopRotation ()
// Invalidate display link
self.displayLink?.invalidate()
self.displayLink = nil
// Called everytime the display is refreshed
@objc func onFrameInterval (displayLink: CADisplayLink)
// Get frames per second
let framesPerSecond = Double(displayLink.preferredFramesPerSecond)
// Based on fps, calculate how much target view should spin each interval
let rotationsPerSecond = Double(3)
let anglePerSecond = rotationsPerSecond * (2 * Double.pi)
let anglePerInterval = CGFloat(anglePerSecond / framesPerSecond)
// Rotate target view to match the current angle of the interval
self.targetView.layer.transform = CATransform3DRotate(self.targetView.layer.transform, anglePerInterval, 0, 0, 1)
【讨论】:
【参考方案8】:通过递归调用避免完成闭包!
这次聚会有点晚了,但使用 UIView 关键帧动画和每个关键帧的不同旋转阶段,加上设置动画曲线效果很好。这是一个 UIView 类函数 -
class func rotate360(_ view: UIView, duration: TimeInterval, repeating: Bool = true)
let transform1 = CGAffineTransform(rotationAngle: .pi * 0.75)
let transform2 = CGAffineTransform(rotationAngle: .pi * 1.5)
let animationOptions: UInt
if repeating
animationOptions = UIView.AnimationOptions.curveLinear.rawValue | UIView.AnimationOptions.repeat.rawValue
else
animationOptions = UIView.AnimationOptions.curveLinear.rawValue
let keyFrameAnimationOptions = UIView.KeyframeAnimationOptions(rawValue: animationOptions)
UIView.animateKeyframes(withDuration: duration, delay: 0, options: [keyFrameAnimationOptions, .calculationModeLinear], animations:
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.375)
view.transform = transform1
UIView.addKeyframe(withRelativeStartTime: 0.375, relativeDuration: 0.375)
view.transform = transform2
UIView.addKeyframe(withRelativeStartTime: 0.75, relativeDuration: 0.25)
view.transform = .identity
, completion: nil)
看起来很粗糙,旋转角度很奇怪,但正如操作员和其他人发现的那样,你不能只告诉它旋转 360 度
【讨论】:
【参考方案9】:试试这个对我有用的,我正在旋转一次图像
UIView.animateWithDuration(0.5, delay: 0.0, options: .CurveLinear, animations:
self.imgViewReload.transform = CGAffineTransformRotate(self.imgViewReload.transform, CGFloat(M_PI))
, completion:
(value: Bool) in
UIView.animateWithDuration(0.5, delay: 0.0, options: .CurveLinear, animations:
self.imgViewReload.transform = CGAffineTransformIdentity
, completion: nil)
)
【讨论】:
【参考方案10】:你可以使用这个功能......只要给它视图和持续时间
它有两个动画,第一个将视图旋转 180°,另一个将其旋转到 360°,然后函数调用自身,允许它无限地继续旋转动画
func infinite360Animation(targetView: UIView, duration: Double)
UIView.animate(withDuration: duration/2, delay: 0, options: .curveLinear)
targetView.transform = CGAffineTransform.identity.rotated(by: .pi )
completion: (_) in
UIView.animate(withDuration: duration/2, delay: 0, options: .curveLinear)
targetView.transform = CGAffineTransform.identity.rotated(by: .pi * 2)
completion: (_) in
self.infinite360Animation(targetView: targetView, duration: duration)
然后你可以像这样调用函数
infinite360Animatio(targetView: yourView, duration: 3)
【讨论】:
这并没有回答问题的“无限期”部分。 OP 可以通过“Double.infinity”吗?似乎它不会按预期工作。 也许称它为循环将解决这部分问题。【参考方案11】:在您的 tabBarController 上,确保设置您的委托并执行以下 didSelect 方法:
func tabBarController(_ tabBarController: UITabBarController,
didSelect viewController: UIViewController)
if let selectedItem:UITabBarItem = tabBarController.tabBar.selectedItem
animated(tabBar: tabBarController.tabBar, selectedItem: selectedItem)
fileprivate func animated(tabBar: UITabBar, selectedItem:UITabBarItem)
if let view:UIView = selectedItem.value(forKey: "view") as? UIView
if let currentImageView = view.subviews.first as? UIImageView
rotate(imageView: currentImageView, completion: (completed) in
self.restore(imageView: currentImageView, completion: nil)
)
fileprivate func rotate(imageView:UIImageView, completion:((Bool) ->Void)?)
UIView.animate(withDuration: animationSpeed, delay: 0.0, options: .curveLinear, animations:
imageView.transform = CGAffineTransform.init(rotationAngle: CGFloat.pi)
, completion:
(value: Bool) in
completion?(value)
)
fileprivate func restore(imageView:UIImageView, completion:((Bool) ->Void)?)
UIView.animate(withDuration: animationSpeed, delay: 0.0, options: .curveLinear, animations:
imageView.transform = CGAffineTransform.identity
, completion:
(value: Bool) in
completion?(value)
)
【讨论】:
以上是关于在 Swift 中无限期旋转 360 度视图?的主要内容,如果未能解决你的问题,请参考以下文章
HTML5/CSS3 - 如何制作“无尽”旋转背景 - 360 度全景