我试图旋转一个UIImageView 360度,并在网上看了几个教程。我不能让它们都工作,UIView要么停止,要么跳转到一个新位置。
我怎样才能做到这一点呢?
我最近尝试的是:
[UIView animateWithDuration:1.0
delay:0.0
options:0
animations:^{
imageToMove.transform = CGAffineTransformMakeRotation(M_PI);
}
completion:^(BOOL finished){
NSLog(@"Done!");
}];
但如果我使用2*pi,它根本不会移动(因为它是相同的位置)。如果我尝试只做(180度),它可以工作,但如果我再次调用这个方法,它会向后旋转。
编辑:
[UIView animateWithDuration:1.0
delay:0.0
options:0
animations:^{
[UIView setAnimationRepeatCount:HUGE_VALF];
[UIView setAnimationBeginsFromCurrentState:YES];
imageToMove.transform = CGAffineTransformMakeRotation(M_PI);
}
completion:^(BOOL finished){
NSLog(@"Done!");
}];
也不管用。它会转到180度,暂停一秒钟,然后在重新开始之前重置回0度。
我认为你最好添加一个UIVIew Category:
#import <QuartzCore/QuartzCore.h>
#import "UIView+Rotate.h"
实现UIView(旋转)
(void)remrotate360WithDuration:(CGFloat)duration repeatCount: (float)repeatCount
{
CABasicAnimation *fullRotation;
fullRotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
fullRotation.fromValue = [NSNumber numberWithFloat:0];
fullRotation.toValue = [NSNumber numberWithFloat:(2*M_PI)];
// fullRotation.toValue = [NSNumber numberWithFloat:-(2*M_PI)]; // added this minus sign as i want to rotate it to anticlockwise
fullRotation.duration = duration;
fullRotation.speed = 2.0f; // Changed rotation speed
if (repeatCount == 0)
fullRotation.repeatCount = MAXFLOAT;
else
fullRotation.repeatCount = repeatCount;
[self.layer addAnimation:fullRotation forKey:@"360"];
}
不使用此方法:)
(void)remstopAllAnimations
{
[self.layer removeAllAnimations];
};
(void)rempauseAnimations
{
[self rempauseLayer:self.layer];
}
(void)remresumeAnimations
{
[self remresumeLayer:self.layer];
}
(void)rempauseLayer:(CALayer *)layer
{
CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
layer.speed = 0.0;
layer.timeOffset = pausedTime;
}
(void)remresumeLayer:(CALayer *)layer
{
CFTimeInterval pausedTime = [layer timeOffset];
layer.speed = 1.0;
layer.timeOffset = 0.0;
layer.beginTime = 0.0;
CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
layer.beginTime = timeSincePause;
}
Nate上面的答案是理想的停止和开始动画,并提供了一个更好的控制。我很好奇为什么你的没用,而他的有用。我想在这里分享我的发现和一个更简单的代码版本,它可以使UIView连续动画而不停顿。
这是我用的代码,
- (void)rotateImageView
{
[UIView animateWithDuration:1 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
[self.imageView setTransform:CGAffineTransformRotate(self.imageView.transform, M_PI_2)];
}completion:^(BOOL finished){
if (finished) {
[self rotateImageView];
}
}];
}
我使用“CGAffineTransformRotate”而不是“CGAffineTransformMakeRotation”,因为前者返回的结果是随着动画的进行而保存的。这将防止在动画期间视图的跳跃或重置。
另一件事是不要使用'UIViewAnimationOptionRepeat'因为在动画的结尾,在它开始重复之前,它会重置变换,使视图跳回它的原始位置。不是重复,而是递归,这样转换就永远不会重置为原始值,因为动画块实际上永远不会结束。
最后一件事是,你必须以90度(M_PI / 2)的步伐转换视图,而不是360度或180度(2*M_PI或M_PI)。因为变换是正弦和余弦值的矩阵乘法。
t' = [ cos(angle) sin(angle) -sin(angle) cos(angle) 0 0 ] * t
所以,假设你使用180度变换,cos(180)产生-1,使得视图每次都在相反的方向变换(如果你把变换的弧度值改为M_PI, Note-Nate的答案也会有这个问题)。360度转换只是要求视图保持在原来的位置,因此你根本看不到任何旋转。
使用UIView执行360度动画有以下几种不同的方法。
使用CABasicAnimation
var rotationAnimation = CABasicAnimation()
rotationAnimation = CABasicAnimation.init(keyPath: "transform.rotation.z")
rotationAnimation.toValue = NSNumber(value: (Double.pi))
rotationAnimation.duration = 1.0
rotationAnimation.isCumulative = true
rotationAnimation.repeatCount = 100.0
view.layer.add(rotationAnimation, forKey: "rotationAnimation")
下面是UIView的一个扩展函数,它处理启动和停止旋转操作:
extension UIView {
// Start rotation
func startRotation() {
let rotation = CABasicAnimation(keyPath: "transform.rotation.z")
rotation.fromValue = 0
rotation.toValue = NSNumber(value: Double.pi)
rotation.duration = 1.0
rotation.isCumulative = true
rotation.repeatCount = FLT_MAX
self.layer.add(rotation, forKey: "rotationAnimation")
}
// Stop rotation
func stopRotation() {
self.layer.removeAnimation(forKey: "rotationAnimation")
}
}
现在使用UIView。动画关闭:
UIView.animate(withDuration: 0.5, animations: {
view.transform = CGAffineTransform(rotationAngle: (CGFloat(Double.pi))
}) { (isAnimationComplete) in
// Animation completed
}
如果你想要做的只是无休止地旋转图像,这很好,而且非常简单:
NSTimeInterval duration = 10.0f;
CGFloat angle = M_PI / 2.0f;
CGAffineTransform rotateTransform = CGAffineTransformRotate(imageView.transform, angle);
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionRepeat| UIViewAnimationOptionCurveLinear animations:^{
imageView.transform = rotateTransform;
} completion:nil];
根据我的经验,这是完美的,但要确保你的图像能够在没有任何偏移的情况下围绕其中心旋转,否则图像动画将“跳跃”一旦它到达PI。
要改变旋转的方向,改变角度的符号(angle *= -1)。
@AlexPretzlav的更新评论让我重新审视了这个问题,我意识到当我写这篇文章时,我旋转的图像是沿着垂直和水平轴镜像的,这意味着图像确实只旋转了90度,然后重置,尽管它看起来像在继续旋转。
所以,如果你的图像像我的一样,这将工作得很好,然而,如果图像不是对称的,你会注意到90度后“snap”回到原来的方向。
要旋转非对称图像,最好使用公认的答案。
这些不太优雅的解决方案之一,如下所示,将真正旋转图像,但当动画重新启动时可能会有明显的口吃:
- (void)spin
{
NSTimeInterval duration = 0.5f;
CGFloat angle = M_PI_2;
CGAffineTransform rotateTransform = CGAffineTransformRotate(self.imageView.transform, angle);
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
self.imageView.transform = rotateTransform;
} completion:^(BOOL finished) {
[self spin];
}];
}
你也可以像@richard-j-ross-iii建议的那样只用块来做,但你会得到一个保留循环警告,因为块正在捕获自己:
__block void(^spin)() = ^{
NSTimeInterval duration = 0.5f;
CGFloat angle = M_PI_2;
CGAffineTransform rotateTransform = CGAffineTransformRotate(self.imageView.transform, angle);
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
self.imageView.transform = rotateTransform;
} completion:^(BOOL finished) {
spin();
}];
};
spin();
创建动画
- (CABasicAnimation *)spinAnimationWithDuration:(CGFloat)duration clockwise:(BOOL)clockwise repeat:(BOOL)repeats
{
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
anim.toValue = clockwise ? @(M_PI * 2.0) : @(M_PI * -2.0);
anim.duration = duration;
anim.cumulative = YES;
anim.repeatCount = repeats ? CGFLOAT_MAX : 0;
return anim;
}
将它添加到这样的视图中
CABasicAnimation *animation = [self spinAnimationWithDuration:1.0 clockwise:YES repeat:YES];
[self.spinningView.layer addAnimation:animation forKey:@"rotationAnimation"];
这个答案有什么不同?如果你的大部分函数都返回对象,而不是在这里和那里操作一些对象,你会有更干净的代码。