2012-01-09 88 views
22

目前我有一個2048x435雲的圖像,使用CABasicAnimation滾動橫跨1024x435的Landscaped定向UIImageView。雲圖像應該滾動,但是我在嘗試獲取重複的雲圖像以連接到當前雲圖像的背面時遇到了一些麻煩,以便在雲圖像之間沒有間隙。我一直在努力尋找解決方案,所以任何幫助將不勝感激。我目前的代碼:動畫無縫循環中的圖像的無限滾動

在Xcode 4.2上針對iOS 5開發,具有ARC非故事板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]; 
} 
+0

如何讓這個循環在從後臺返回後繼續(最小化應用程序)? – Mutawe 2012-11-05 13:40:52

回答

57

你說你的圖像是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); 

該層的寬度必須是圖像的寬度加上含有視圖的寬度。這樣,當我們滾動圖層以便圖像的右邊緣可見時,圖像的另一個副本將被繪製到第一個副本的右邊。

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); 

動畫設置的其餘部分與您的代碼相同。我改變了持續時間爲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方法。我們需要在應用程序進入前臺時調用該方法。

viewDidAppear:,我們就可以開始觀測應用已經進入前臺,它告訴我們的通知:

- (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]; 
} 
+1

這很奇妙!感謝您的深入解釋! – r00tb0x 2012-01-09 21:54:40

+0

如何使這個循環在從後臺取回後繼續(最小化應用程序)? – Mutawe 2012-11-05 13:39:33

+0

@rob mauoff請幫助 – Mutawe 2012-11-06 06:13:33

6

羅布,你搖滾兄弟。我正在尋找一種方法來做同樣的事情,但垂直。在閱讀上面的答案後,我沒有任何問題調整以適應我的需求。對於任何人都可以在這裏結束了對他們的追捕垂直解決方案,這是我結束了,上面仿照:

- (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"]; 
} 
4

與垂直和水平滾動選項原液

// 
// 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