Objective c 在无缝循环中设置图像无限滚动的动画

Objective c 在无缝循环中设置图像无限滚动的动画,objective-c,xcode,cocoa-touch,ipad,Objective C,Xcode,Cocoa Touch,Ipad,目前,我有一张2048x435的云的图像,它使用CABasicAnimation在1024x435的景观导向UIImageView上滚动。云图像按其应有的方式滚动,但我在尝试获取一个复制的云图像以连接到当前云图像的背面时遇到了一些困难,以便在云图像之间并没有间隙。我已经挣扎了大约一天,试图找到一个解决方案,所以任何帮助都将不胜感激。我当前的代码: 在用于iOS 5的Xcode 4.2上开发,采用弧形非故事板ipad景观定向 -(void)cloudScroll { UIImage *cl

目前,我有一张2048x435的云的图像,它使用CABasicAnimation在1024x435的景观导向UIImageView上滚动。云图像按其应有的方式滚动,但我在尝试获取一个复制的云图像以连接到当前云图像的背面时遇到了一些困难,以便在云图像之间并没有间隙。我已经挣扎了大约一天,试图找到一个解决方案,所以任何帮助都将不胜感激。我当前的代码:

在用于iOS 5的Xcode 4.2上开发,采用弧形非故事板ipad景观定向

-(void)cloudScroll
{
    UIImage *cloudsImage = [UIImage imageNamed:@"TitleClouds.png"];
    CALayer *cloud = [CALayer layer];
    cloud.contents = (id)cloudsImage.CGImage;
    cloud.bounds = CGRectMake(0, 0, cloudsImage.size.width, cloudsImage.size.height);
    cloud.position = CGPointMake(self.view.bounds.size.width / 2, cloudsImage.size.height / 2);
    [cloudsImageView.layer addSublayer:cloud];

    CGPoint startPt = CGPointMake(self.view.bounds.size.width + cloud.bounds.size.width / 2, cloud.position.y);
    CGPoint endPt = CGPointMake(cloud.bounds.size.width / -2, cloud.position.y);
    CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"position"];
    anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
    anim.fromValue = [NSValue valueWithCGPoint:startPt];
    anim.toValue = [NSValue valueWithCGPoint:endPt];
    anim.repeatCount = HUGE_VALF;
    anim.duration = 60.0;
    [cloud addAnimation:anim forKey:@"position"];
}

-(void)viewDidLoad
{
    [self cloudScroll];
    [super viewDidLoad];
}

您说您的图像宽2048,视图宽1024。我不知道这是否意味着您复制了1024宽图像的内容以生成2048宽的图像

不管怎样,这是我的建议。我们需要将云层及其动画存储在实例变量中:

@implementation ViewController {
    CALayer *cloudLayer;
    CABasicAnimation *cloudLayerAnimation;
}
我们没有将云层的内容设置为云图像,而是将其背景颜色设置为从图像创建的图案颜色。这样,我们可以将层的边界设置为我们想要的任何值,并且图像将平铺以填充边界:

-(void)cloudScroll {
    UIImage *cloudsImage = [UIImage imageNamed:@"TitleClouds.png"];
    UIColor *cloudPattern = [UIColor colorWithPatternImage:cloudsImage];
    cloudLayer = [CALayer layer];
    cloudLayer.backgroundColor = cloudPattern.CGColor;
但是,CALayer坐标系将原点放在左下角而不是左上角,Y轴向上递增。这意味着图案将被颠倒绘制。我们可以通过翻转Y轴来修复此问题:

    cloudLayer.transform = CATransform3DMakeScale(1, -1, 1);
默认情况下,层的定位点位于其中心。这意味着设置图层的位置将设置其中心的位置。通过设置图层左上角的位置,可以更轻松地定位图层。我们可以将其定位点移动到左上角:

    cloudLayer.anchorPoint = CGPointMake(0, 1);
    CGPoint startPoint = CGPointZero;
层的宽度需要是图像的宽度加上包含视图的宽度。这样,当我们滚动图层以便看到图像的右边缘时,图像的另一个副本将被绘制到第一个副本的右侧

    CGSize viewSize = self.cloudsImageView.bounds.size;
    cloudLayer.frame = CGRectMake(0, 0, cloudsImage.size.width + viewSize.width, viewSize.height);
现在,我们准备将图层添加到视图中:

    [self.cloudsImageView.layer addSublayer:cloudLayer];
现在,让我们设置动画。请记住,我们更改了层的定位点,因此可以通过设置其左上角的位置来控制其位置。我们希望层的左上角从视图的左上角开始:

    cloudLayer.anchorPoint = CGPointMake(0, 1);
    CGPoint startPoint = CGPointZero;
我们希望层的左上角向左移动图像的宽度:

    CGPoint endPoint = CGPointMake(-cloudsImage.size.width, 0);
动画设置的其余部分与代码相同。我将测试的持续时间更改为3秒:

    cloudLayerAnimation = [CABasicAnimation animationWithKeyPath:@"position"];
    cloudLayerAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
    cloudLayerAnimation.fromValue = [NSValue valueWithCGPoint:startPoint];
    cloudLayerAnimation.toValue = [NSValue valueWithCGPoint:endPoint];
    cloudLayerAnimation.repeatCount = HUGE_VALF;
    cloudLayerAnimation.duration = 3.0;
我们将调用另一种方法将动画实际附加到层:

    [self applyCloudLayerAnimation];
}
以下是应用动画的方法:

- (void)applyCloudLayerAnimation {
    [cloudLayer addAnimation:cloudLayerAnimation forKey:@"position"];
}
当应用程序进入后台时(因为用户切换到另一个应用程序),系统将从云层删除动画。所以当我们再次进入前景时,我们需要重新连接它。这就是为什么我们有
applyCloudLayerAnimation
方法。我们需要在应用程序进入前台时调用该方法

视图显示:
中,我们可以开始观察通知,通知我们应用程序已进入前台:

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];
}
当视图消失或视图控制器解除分配时,我们需要停止观察通知:

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil];
}

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillEnterForegroundNotification object:nil];
}
当视图控制器实际收到通知时,我们需要再次应用动画:

- (void)applicationWillEnterForeground:(NSNotification *)note {
    [self applyCloudLayerAnimation];
}
以下是便于复制和粘贴的所有代码:

- (void)viewDidLoad {
    [self cloudScroll];
    [super viewDidLoad];
}

-(void)cloudScroll {
    UIImage *cloudsImage = [UIImage imageNamed:@"TitleClouds.png"];
    UIColor *cloudPattern = [UIColor colorWithPatternImage:cloudsImage];
    cloudLayer = [CALayer layer];
    cloudLayer.backgroundColor = cloudPattern.CGColor;

    cloudLayer.transform = CATransform3DMakeScale(1, -1, 1);

    cloudLayer.anchorPoint = CGPointMake(0, 1);

    CGSize viewSize = self.cloudsImageView.bounds.size;
    cloudLayer.frame = CGRectMake(0, 0, cloudsImage.size.width + viewSize.width, viewSize.height);

    [self.cloudsImageView.layer addSublayer:cloudLayer];

    CGPoint startPoint = CGPointZero;
    CGPoint endPoint = CGPointMake(-cloudsImage.size.width, 0);
    cloudLayerAnimation = [CABasicAnimation animationWithKeyPath:@"position"];
    cloudLayerAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
    cloudLayerAnimation.fromValue = [NSValue valueWithCGPoint:startPoint];
    cloudLayerAnimation.toValue = [NSValue valueWithCGPoint:endPoint];
    cloudLayerAnimation.repeatCount = HUGE_VALF;
    cloudLayerAnimation.duration = 3.0;
    [self applyCloudLayerAnimation];
}

- (void)applyCloudLayerAnimation {
    [cloudLayer addAnimation:cloudLayerAnimation forKey:@"position"];
}

- (void)viewDidUnload {
    [self setCloudsImageView:nil];
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil];
}

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillEnterForegroundNotification object:nil];
}

- (void)applicationWillEnterForeground:(NSNotification *)note {
    [self applyCloudLayerAnimation];
}

罗布,你这个摇滚兄弟。我正在寻找一种方法来做同样的事情,但垂直。在阅读了你上面的答案后,我没有问题调整它以适应我的需要。对于任何可能在这里寻找垂直解决方案的人来说,这就是我最终得到的,仿照上面的模式:

- (IBAction)animateBackground6
{
    UIImage *backgroundImage = [UIImage imageNamed:@"space.png"];
    UIColor *backgroundPattern = [UIColor colorWithPatternImage:backgroundImage];

    CALayer *background = [CALayer layer];
    background.backgroundColor = backgroundPattern.CGColor;
    background.transform = CATransform3DMakeScale(1, -1, 1);
    background.anchorPoint = CGPointMake(0, 1);

    CGSize viewSize = self.backgroundImageView.bounds.size;
    background.frame = CGRectMake(0, 0, viewSize.width,  backgroundImage.size.height +   viewSize.height);
    [self.backgroundImageView.layer addSublayer:background];

    CGPoint startPoint = CGPointZero;
    CGPoint endPoint = CGPointMake(0, -backgroundImage.size.height);

    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
    animation.fromValue = [NSValue valueWithCGPoint:endPoint];
    animation.toValue = [NSValue valueWithCGPoint:startPoint];
    animation.repeatCount = HUGE_VALF;
    animation.duration = 5.0;
    [background addAnimation:animation forKey:@"position"];
}

具有垂直和水平滚动选项的原始解决方案

//
//  originally found here: http://stackoverflow.com/questions/8790079/animate-infinite-scrolling-of-an-image-in-a-seamless-loop
//

#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>

@interface TiledCloundScrollViewController : UIViewController {
    CALayer *cloudLayer;
    CABasicAnimation *cloudLayerAnimation;

    UIImage *cloudsImage;
    BOOL verticalScroll;
    CFTimeInterval animationDuration;
}

- (id) initWithImage:(UIImage*)cloudsImage verticalScroll:(BOOL)verticalScroll animationDuration:(CFTimeInterval)animationDuration;

@end



#import "TiledCloundScrollViewController.h"

@interface TiledCloundScrollViewController ()
@end

@implementation TiledCloundScrollViewController

- (id) init {
    [self doesNotRecognizeSelector:_cmd];
    return nil;
}

- (id) initWithImage:(UIImage*)image verticalScroll:(BOOL)vScroll animationDuration:(CFTimeInterval)duration {
    self = [super init];
    if (self ) {
        cloudsImage = image;
        verticalScroll = vScroll;
        animationDuration = duration;
    }
    return self;
}

- (void) viewDidLoad {
    [super viewDidLoad];

    self.view.clipsToBounds = YES;
    const CGSize viewSize = self.view.bounds.size;
    const CGSize imageSize = cloudsImage.size;

    UIColor *cloudPattern = [UIColor colorWithPatternImage:cloudsImage];
    cloudLayer = [CALayer layer];
    cloudLayer.backgroundColor = cloudPattern.CGColor;
    cloudLayer.transform = CATransform3DMakeScale(1, -1, 1);
    cloudLayer.anchorPoint = CGPointMake(0, 1);
    [self.view.layer addSublayer:cloudLayer];

    CGPoint startPoint = CGPointZero;
    CGPoint endPoint;
    if (verticalScroll) {
        endPoint = CGPointMake(0, -imageSize.height);
        cloudLayer.frame = CGRectMake(0, 0, viewSize.width, viewSize.height + imageSize.height);
    } else {
        endPoint = CGPointMake(-imageSize.width, 0);
        cloudLayer.frame = CGRectMake(0, 0, viewSize.width + imageSize.width, viewSize.height);
    }

    cloudLayerAnimation = [CABasicAnimation animationWithKeyPath:@"position"];
    cloudLayerAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
    cloudLayerAnimation.fromValue = [NSValue valueWithCGPoint:startPoint];
    cloudLayerAnimation.toValue = [NSValue valueWithCGPoint:endPoint];
    cloudLayerAnimation.repeatCount = HUGE_VALF;
    cloudLayerAnimation.duration = animationDuration;
    [self applyCloudLayerAnimation];
}

- (void) viewDidUnload {
    cloudLayer = nil;
    cloudLayerAnimation = nil;
    [super viewDidUnload];
}

- (void) applyCloudLayerAnimation {
    [cloudLayer addAnimation:cloudLayerAnimation forKey:@"position"];
}

- (void)applicationWillEnterForeground:(NSNotification *)note {
    [self applyCloudLayerAnimation];
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil];
}

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillEnterForegroundNotification object:nil];
}


@end
//
//最初在这里发现:http://stackoverflow.com/questions/8790079/animate-infinite-scrolling-of-an-image-in-a-seamless-loop
//
#进口
#进口
@界面平铺CloundScrollViewController:UIViewController{
CALayer*云层;
卡巴斯基化*云层化;
UIImage*cloudsImage;
垂直卷轴;
CFTimeInterval动画持续时间;
}
-(id)initWithImage:(UIImage*)cloudsImage垂直滚动:(BOOL)垂直滚动动画持续时间:(CFTimeInterval)动画持续时间;
@结束
#导入“TiledCloundScrollViewController.h”
@接口平铺CloundScrollViewController()
@结束
@实现TiledCloundScrollViewController
-(id)init{
[自我识别选择器:_cmd];
返回零;
}
-(id)initWithImage:(UIImage*)图像垂直滚动:(BOOL)vScroll动画持续时间:(CFTimeInterval)持续时间{
self=[super init];
如果(自我){
cloudsImage=图像;
垂直滚动=垂直滚动;
animationDuration=持续时间;
}
回归自我;
}
-(无效)viewDidLoad{
[超级视图下载];
self.view.clipstobunds=是;
const CGSize viewSize=self.view.bounds.size;
const CGSize imageSize=cloudsImage.size;
UIColor*cloudPattern=[uicolorWithPatternImage:cloudsImage];
云层=[CALayer层];
cloudLayer.backgroundColor=cloudPattern.CGColor;
cloudLayer.transform=CATTransferM3dMakeScale(1,-1,1);
cloudLayer.ancorpoint=CGPointMake(0,1);
[self.view.layer addSublayer:cloudLayer];
CGPoint startPoint=CGPointZero;
CG点端点;
如果(垂直滚动){
端点=CGPointMake(0,-imageSize.height);
cloudLayer.frame=CGRectMake(0,0,viewSize.width,viewSize.height+imageSize.height);
}否则{
端点=CGPointMake(-imageSize.width,0);
cloudLayer.frame=CGRectMake(0,0,viewSize.width+imageSize.width,viewSize.height);
}
cloudLayerAnimation=[CABasicAnimation animationWithKeyPath:@“位置”];
cloudLayerAnimation.timingFunction=[CamediaTimingFunctionWithName:kCAMediaTimingFunctionLinear];
cloudLayerAnimation.fromValue=[NSValue valueWithCGPoint:startPoint];
cloudLayerAnimation.toValue=[NSValue Value WithCGP