对于给定的对象数组,如何同时 运行 多个 UIAnimation 块?
How do I run multiple UIAnimation blocks at the same time for a given array of objects?
我需要在屏幕上移动5个图像并做过渡效果,例如旋转->旋转动画完成时:移动(移动完成后:然后重复过程)
我可以得到 1 张图像来执行此操作,效果很好。
我遇到的问题是我需要对 5 张图像进行处理;要求是所有图像(或图像视图)都需要同时 运行 的动画。
我使用了一个自定义对象,里面有一个 UIImageView
-(void)stopRepeatingAnimationForView:(UIView *)view
{
self.enableRepeatingAnimation = NO;
[view.layer removeAllAnimations];
}
- (void)startRepeatingAnimationForView:(UIView *)view
{
self.enableRepeatingAnimation = YES;
[self repeatingAnimationForView:view];
}
- (void)repeatingAnimationForView:(UIView *)view
{
//VICAirplane *planeObj = [self.airplanes objectAtIndex:0];
for (VICAirplane *planeObj in self.airplanes) {
[UIView animateWithDuration:3
delay:1
options:UIViewAnimationOptionCurveLinear
animations:^{
planeObj.imageView.transform = CGAffineTransformRotate(planeObj.imageView.transform, planeObj.angleToRotate);
} completion:^(BOOL finished) {
if (finished==YES) {
[UIView animateWithDuration:5
delay:0.0
options:UIViewAnimationOptionCurveLinear
animations:^{
planeObj.imageView.center = planeObj.rotateToLocation;
} completion:^(BOOL finished) {
if (finished==YES) {
if ( self.enableRepeatingAnimation )
{
CGPoint rotateToLocation = [self generateRandomLocation];
planeObj.rotateToLocation = rotateToLocation;
[self performSelector:@selector(repeatingAnimationForView:) withObject:view afterDelay:0];
}
}
}];
}
}];
} // next
}
如果删除数组中的循环或简单地使其成为 1 个长度的数组,则动画效果很好。
但是如果我同时添加多个动画,它们就会开始失去完成状态,最终会变得一团糟。
我想做的是:
- 循环浏览我的 5 张图片
- 在每个图像上执行我的旋转 -> 移动 -> 重复(永远)动画
但我不确定如何让它适用于存储在数组中的多个 uiimageviews
有办法吗?
如果我正确理解你的问题,下面的代码应该可以满足你的要求。它旨在按以下顺序执行以下操作:
- 在相同的时间和相同的持续时间内,将 view/airplane/whatever 数组中的 所有 项旋转到新的旋转方向。
- 将 view/airplane/whatever 数组中的 所有 项同时并在相同的持续时间内翻译到它们的新位置。
- 在#2 的末尾,从#1 开始重复。
现在,对于我的代码,我创建了 VICAirplane
作为 UIView
的一个简单子类,它有一个 属性:
@property (assign,nonatomic) CGPoint rotateToLocation
.
基本上,您尝试使用一个 for
循环来迭代您的对象,但如果您在每个动画期间迭代数组,效果会更好。您绝对可以按照我在下面显示的方式链接它们,但您也可以为动画链的每个 "link" 创建单独的方法,然后每个方法遍历数组一次。在任何一种情况下,您都需要迭代数组 in/during 动画块,而不是在它之外。当您在它之外进行迭代时(如上面的代码所做的那样),您正在为每个对象创建一个单独的动画块,所有这些都将被独立处理。
无论如何,下面的代码创建了 5 个旋转的彩色方块,然后在连续的动画循环中以随机方式平移。
// VICAirplane.h
#import <UIKit/UIKit.h>
@interface VICAirplane : UIView
@property (assign, nonatomic) CGPoint rotateToLocation;
@end
// VICAirplane.m
#import "VICAirplane.h"
@implementation VICAirplane
@end
// ViewController.h
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
// ViewController.m
#import "ViewController.h"
#import "VICAirplane.h"
@interface ViewController () {
}
@property (strong, nonatomic) NSMutableArray *views;
@property (assign, nonatomic) BOOL enableRepeatingAnimation;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self setupUserInterface];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self startRepeatingAnimation];
}
- (void)setupUserInterface {
self.views = [NSMutableArray array];
for (int i = 0; i < 5; i = i + 1) {
VICAirplane *newView = [[VICAirplane alloc] initWithFrame:CGRectMake((i * 100) + 20, (i * 100) + 20, 80, 80)];
switch (i % 4) {
case 0:
newView.backgroundColor = [UIColor blueColor];
break;
case 1:
newView.backgroundColor = [UIColor redColor];
break;
case 2:
newView.backgroundColor = [UIColor greenColor];
break;
case 3:
newView.backgroundColor = [UIColor brownColor];
break;
case 4:
newView.backgroundColor = [UIColor purpleColor];
break;
default:
break;
}
[self.views addObject:newView];
[self.view addSubview:newView];
}
}
- (CGPoint)generateRandomLocation {
CGFloat x = (CGFloat)arc4random_uniform(600);
CGFloat y = (CGFloat)arc4random_uniform(600);
return CGPointMake(x, y);
}
-(void)stopRepeatingAnimation {
self.enableRepeatingAnimation = NO;
[self.view.layer removeAllAnimations];
}
- (void)startRepeatingAnimation {
self.enableRepeatingAnimation = YES;
for (VICAirplane *subview in self.views) {
subview.rotateToLocation = [self generateRandomLocation];
}
[self repeatingAnimation];
}
- (void)repeatingAnimation {
[UIView animateWithDuration:3
delay:1
options:UIViewAnimationOptionCurveLinear
animations:^{
for (UIView *subview in self.views) {
// Just a random rotation between -2π and 2π
CGFloat rotationAngle = (arc4random_uniform(400 * M_PI) - (200 * M_PI)) / 100;
subview.transform = CGAffineTransformRotate(subview.transform, rotationAngle);
}
}
completion:^(BOOL finished) {
if (finished==YES) {
[UIView animateWithDuration:5
delay:0.0
options:UIViewAnimationOptionCurveLinear
animations:^{
for (VICAirplane *subview in self.views) {
subview.center = subview.rotateToLocation;
}
}
completion:^(BOOL finished) {
if (finished==YES) {
if (self.enableRepeatingAnimation) {
for (VICAirplane *subview in self.views) {
subview.rotateToLocation = [self generateRandomLocation];
}
[self performSelector:@selector(repeatingAnimation) withObject:nil afterDelay:0.0f];
}
}
}
];
}
}
];
}
@end
我只是将我的循环放在应用程序的不同部分,现在它运行得更好了。
原来我是这样做的:
- (void)repeatingAnimationForView:(UIView *)view
{
for (VICAirplane *planeObj in self.airplanes) {
}
}
我不需要将 for 循环放入我的 startRepeatingAnimationForView
方法中,只需将参数传递给相同的方法
相反,我应该把它放在这里(我现在已经完成并且比原来的效果更好)
-(void)stopRepeatingAnimationForView:(UIView *)view
{
self.enableRepeatingAnimation = NO;
[view.layer removeAllAnimations];
}
- (void)startRepeatingAnimationForView:(UIView *)view
{
self.enableRepeatingAnimation = YES;
for (VICAirplane *planeObj in self.airplanes) {
[self repeatAnimationWithParams:@{@"view":view, @"planeObj": planeObj}];
}
}
-(void) repeatAnimationWithParams:(NSDictionary *)params
{
VICAirplane *planeObj = params[@"planeObj"];
[UIView animateWithDuration:2
delay:1
options:UIViewAnimationOptionCurveLinear
animations:^{
planeObj.imageView.transform = CGAffineTransformRotate(planeObj.imageView.transform, planeObj.angleToRotate);
} completion:^(BOOL finished) {
if (finished==YES) {
[UIView animateWithDuration:5
delay:0.0
options:UIViewAnimationOptionCurveLinear
animations:^{
planeObj.imageView.center = planeObj.rotateToLocation;
} completion:^(BOOL finished) {
if (finished==YES) {
if ( self.enableRepeatingAnimation )
{
CGPoint rotateToLocation = [self generateRandomLocation];
planeObj.rotateToLocation = rotateToLocation;
[self performSelector:@selector(repeatAnimationWithParams:)
withObject:params
afterDelay:0];
}
}
}];
}
}];
}
我需要在屏幕上移动5个图像并做过渡效果,例如旋转->旋转动画完成时:移动(移动完成后:然后重复过程)
我可以得到 1 张图像来执行此操作,效果很好。
我遇到的问题是我需要对 5 张图像进行处理;要求是所有图像(或图像视图)都需要同时 运行 的动画。
我使用了一个自定义对象,里面有一个 UIImageView
-(void)stopRepeatingAnimationForView:(UIView *)view
{
self.enableRepeatingAnimation = NO;
[view.layer removeAllAnimations];
}
- (void)startRepeatingAnimationForView:(UIView *)view
{
self.enableRepeatingAnimation = YES;
[self repeatingAnimationForView:view];
}
- (void)repeatingAnimationForView:(UIView *)view
{
//VICAirplane *planeObj = [self.airplanes objectAtIndex:0];
for (VICAirplane *planeObj in self.airplanes) {
[UIView animateWithDuration:3
delay:1
options:UIViewAnimationOptionCurveLinear
animations:^{
planeObj.imageView.transform = CGAffineTransformRotate(planeObj.imageView.transform, planeObj.angleToRotate);
} completion:^(BOOL finished) {
if (finished==YES) {
[UIView animateWithDuration:5
delay:0.0
options:UIViewAnimationOptionCurveLinear
animations:^{
planeObj.imageView.center = planeObj.rotateToLocation;
} completion:^(BOOL finished) {
if (finished==YES) {
if ( self.enableRepeatingAnimation )
{
CGPoint rotateToLocation = [self generateRandomLocation];
planeObj.rotateToLocation = rotateToLocation;
[self performSelector:@selector(repeatingAnimationForView:) withObject:view afterDelay:0];
}
}
}];
}
}];
} // next
}
如果删除数组中的循环或简单地使其成为 1 个长度的数组,则动画效果很好。
但是如果我同时添加多个动画,它们就会开始失去完成状态,最终会变得一团糟。
我想做的是:
- 循环浏览我的 5 张图片
- 在每个图像上执行我的旋转 -> 移动 -> 重复(永远)动画
但我不确定如何让它适用于存储在数组中的多个 uiimageviews
有办法吗?
如果我正确理解你的问题,下面的代码应该可以满足你的要求。它旨在按以下顺序执行以下操作:
- 在相同的时间和相同的持续时间内,将 view/airplane/whatever 数组中的 所有 项旋转到新的旋转方向。
- 将 view/airplane/whatever 数组中的 所有 项同时并在相同的持续时间内翻译到它们的新位置。
- 在#2 的末尾,从#1 开始重复。
现在,对于我的代码,我创建了 VICAirplane
作为 UIView
的一个简单子类,它有一个 属性:
@property (assign,nonatomic) CGPoint rotateToLocation
.
基本上,您尝试使用一个 for
循环来迭代您的对象,但如果您在每个动画期间迭代数组,效果会更好。您绝对可以按照我在下面显示的方式链接它们,但您也可以为动画链的每个 "link" 创建单独的方法,然后每个方法遍历数组一次。在任何一种情况下,您都需要迭代数组 in/during 动画块,而不是在它之外。当您在它之外进行迭代时(如上面的代码所做的那样),您正在为每个对象创建一个单独的动画块,所有这些都将被独立处理。
无论如何,下面的代码创建了 5 个旋转的彩色方块,然后在连续的动画循环中以随机方式平移。
// VICAirplane.h
#import <UIKit/UIKit.h>
@interface VICAirplane : UIView
@property (assign, nonatomic) CGPoint rotateToLocation;
@end
// VICAirplane.m
#import "VICAirplane.h"
@implementation VICAirplane
@end
// ViewController.h
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
// ViewController.m
#import "ViewController.h"
#import "VICAirplane.h"
@interface ViewController () {
}
@property (strong, nonatomic) NSMutableArray *views;
@property (assign, nonatomic) BOOL enableRepeatingAnimation;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self setupUserInterface];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self startRepeatingAnimation];
}
- (void)setupUserInterface {
self.views = [NSMutableArray array];
for (int i = 0; i < 5; i = i + 1) {
VICAirplane *newView = [[VICAirplane alloc] initWithFrame:CGRectMake((i * 100) + 20, (i * 100) + 20, 80, 80)];
switch (i % 4) {
case 0:
newView.backgroundColor = [UIColor blueColor];
break;
case 1:
newView.backgroundColor = [UIColor redColor];
break;
case 2:
newView.backgroundColor = [UIColor greenColor];
break;
case 3:
newView.backgroundColor = [UIColor brownColor];
break;
case 4:
newView.backgroundColor = [UIColor purpleColor];
break;
default:
break;
}
[self.views addObject:newView];
[self.view addSubview:newView];
}
}
- (CGPoint)generateRandomLocation {
CGFloat x = (CGFloat)arc4random_uniform(600);
CGFloat y = (CGFloat)arc4random_uniform(600);
return CGPointMake(x, y);
}
-(void)stopRepeatingAnimation {
self.enableRepeatingAnimation = NO;
[self.view.layer removeAllAnimations];
}
- (void)startRepeatingAnimation {
self.enableRepeatingAnimation = YES;
for (VICAirplane *subview in self.views) {
subview.rotateToLocation = [self generateRandomLocation];
}
[self repeatingAnimation];
}
- (void)repeatingAnimation {
[UIView animateWithDuration:3
delay:1
options:UIViewAnimationOptionCurveLinear
animations:^{
for (UIView *subview in self.views) {
// Just a random rotation between -2π and 2π
CGFloat rotationAngle = (arc4random_uniform(400 * M_PI) - (200 * M_PI)) / 100;
subview.transform = CGAffineTransformRotate(subview.transform, rotationAngle);
}
}
completion:^(BOOL finished) {
if (finished==YES) {
[UIView animateWithDuration:5
delay:0.0
options:UIViewAnimationOptionCurveLinear
animations:^{
for (VICAirplane *subview in self.views) {
subview.center = subview.rotateToLocation;
}
}
completion:^(BOOL finished) {
if (finished==YES) {
if (self.enableRepeatingAnimation) {
for (VICAirplane *subview in self.views) {
subview.rotateToLocation = [self generateRandomLocation];
}
[self performSelector:@selector(repeatingAnimation) withObject:nil afterDelay:0.0f];
}
}
}
];
}
}
];
}
@end
我只是将我的循环放在应用程序的不同部分,现在它运行得更好了。
原来我是这样做的:
- (void)repeatingAnimationForView:(UIView *)view
{
for (VICAirplane *planeObj in self.airplanes) {
}
}
我不需要将 for 循环放入我的 startRepeatingAnimationForView
方法中,只需将参数传递给相同的方法
相反,我应该把它放在这里(我现在已经完成并且比原来的效果更好)
-(void)stopRepeatingAnimationForView:(UIView *)view
{
self.enableRepeatingAnimation = NO;
[view.layer removeAllAnimations];
}
- (void)startRepeatingAnimationForView:(UIView *)view
{
self.enableRepeatingAnimation = YES;
for (VICAirplane *planeObj in self.airplanes) {
[self repeatAnimationWithParams:@{@"view":view, @"planeObj": planeObj}];
}
}
-(void) repeatAnimationWithParams:(NSDictionary *)params
{
VICAirplane *planeObj = params[@"planeObj"];
[UIView animateWithDuration:2
delay:1
options:UIViewAnimationOptionCurveLinear
animations:^{
planeObj.imageView.transform = CGAffineTransformRotate(planeObj.imageView.transform, planeObj.angleToRotate);
} completion:^(BOOL finished) {
if (finished==YES) {
[UIView animateWithDuration:5
delay:0.0
options:UIViewAnimationOptionCurveLinear
animations:^{
planeObj.imageView.center = planeObj.rotateToLocation;
} completion:^(BOOL finished) {
if (finished==YES) {
if ( self.enableRepeatingAnimation )
{
CGPoint rotateToLocation = [self generateRandomLocation];
planeObj.rotateToLocation = rotateToLocation;
[self performSelector:@selector(repeatAnimationWithParams:)
withObject:params
afterDelay:0];
}
}
}];
}
}];
}