首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在无缝循环中以动画方式无限滚动图像

在无缝循环中以动画方式无限滚动图像
EN

Stack Overflow用户
提问于 2012-01-09 22:39:37
回答 3查看 12K关注 0票数 22

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

在Xcode4.2foriPad5上开发,具有ARC非故事板iOS景观方向。

代码语言:javascript
复制
-(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];
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-01-10 03:49:08

你说你的图像是2048宽,你的视野是1024宽。我不知道这是否意味着你已经复制了一个1024宽的图像的内容来制作一个2048宽的图像。

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

代码语言:javascript
复制
@implementation ViewController {
    CALayer *cloudLayer;
    CABasicAnimation *cloudLayerAnimation;
}

我们没有将云层的内容设置为云图像,而是将其背景颜色设置为从图像创建的图案颜色。这样,我们可以将图层的边界设置为我们想要的任何内容,图像将被平铺以填充边界:

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

但是,CALayer的坐标系将原点放在左下角而不是左上角,同时Y轴向上增加。这意味着图案将被颠倒绘制。我们可以通过翻转Y轴来解决这个问题:

代码语言:javascript
复制
    cloudLayer.transform = CATransform3DMakeScale(1, -1, 1);

默认情况下,层的锚点位于其中心。这意味着设置图层的位置将设置其中心的位置。通过设置图层左上角的位置可以更容易地定位图层。我们可以通过将其锚点移动到其左上角来完成此操作:

代码语言:javascript
复制
    cloudLayer.anchorPoint = CGPointMake(0, 1);

层的宽度需要是图像的宽度加上包含视图的宽度。这样,当我们滚动图层以使图像的右边缘进入视图时,图像的另一个副本将绘制到第一个副本的右侧。

代码语言:javascript
复制
    CGSize viewSize = self.cloudsImageView.bounds.size;
    cloudLayer.frame = CGRectMake(0, 0, cloudsImage.size.width + viewSize.width, viewSize.height);

现在我们准备将层添加到视图中:

代码语言:javascript
复制
    [self.cloudsImageView.layer addSublayer:cloudLayer];

现在让我们设置动画。记住,我们改变了层的锚点,所以我们可以通过设置左上角的位置来控制它的位置。我们希望图层的左上角从视图的左上角开始:

代码语言:javascript
复制
    CGPoint startPoint = CGPointZero;

我们希望图层的左上角按图像的宽度向左移动:

代码语言:javascript
复制
    CGPoint endPoint = CGPointMake(-cloudsImage.size.width, 0);

动画设置的其余部分与代码相同。我将持续时间更改为3秒以进行测试:

代码语言:javascript
复制
    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;

我们将调用另一个方法来将动画实际附加到层:

代码语言:javascript
复制
    [self applyCloudLayerAnimation];
}

下面是应用动画的方法:

代码语言:javascript
复制
- (void)applyCloudLayerAnimation {
    [cloudLayer addAnimation:cloudLayerAnimation forKey:@"position"];
}

当应用程序进入后台(因为用户切换到另一个应用程序)时,系统将从云层中删除动画。因此,当我们再次进入前台时,我们需要重新附加它。这就是我们使用applyCloudLayerAnimation方法的原因。当应用程序进入前台时,我们需要调用该方法。

viewDidAppear:中,我们可以开始观察通知,告诉我们应用程序已经进入前台:

代码语言:javascript
复制
- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];
}

当我们的视图消失,或者当视图控制器被释放时,我们需要停止观察通知:

代码语言:javascript
复制
- (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];
}

当视图控制器实际收到通知时,我们需要再次应用动画:

代码语言:javascript
复制
- (void)applicationWillEnterForeground:(NSNotification *)note {
    [self applyCloudLayerAnimation];
}

为了便于复制和粘贴,下面是所有代码:

代码语言:javascript
复制
- (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];
}
票数 57
EN

Stack Overflow用户

发布于 2012-10-06 16:28:56

罗伯,你这个摇滚兄弟。我正在寻找一种方法来做同样的事情,但是是垂直的。在读完你上面的答案后,我可以根据我的需要对其进行调整。对于任何可能最终在这里寻找垂直解决方案的人来说,这就是我最终得到的,仿照上面的:

代码语言:javascript
复制
- (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"];
}
票数 6
EN

Stack Overflow用户

发布于 2013-03-21 01:23:12

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

代码语言:javascript
复制
//
//  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
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8790079

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档