在无缝循环中动画无限滚动图像 [英] Animate infinite scrolling of an image in a seamless loop

查看:114
本文介绍了在无缝循环中动画无限滚动图像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目前我有一个2048x435的云的图像,使用CABasicAnimation滚动横跨一个园景导向的UIImageView的1024x435。云图像滚动,因为它应该,但我有一些麻烦,试图获得一个重复的云图像连接到当前云图像的背面,使云图像之间没有间隙。我一直在努力寻找一个解决方案一天,所以任何帮助将非常感激。我当前的代码:

Currently I have an image of clouds of 2048x435 that scrolls across a Landscaped oriented UIImageView of 1024x435 using CABasicAnimation. The cloud image scrolls as it should, however I am having some trouble trying to to get a duplicate clouds image to connect to the back of the the current clouds image so that there is no gap between the clouds images. I've been struggling for about a day trying to find a solution, so any help would be greatly appreciated. My current code:

在Xcode 4.2上开发iOS 5,使用ARC非故事板ipad园景取向。

developing on Xcode 4.2 for iOS 5 with ARC non-storyboard ipad landscaped orientation.

-(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宽的图片。

You say that your image is 2048 wide and your view is 1024 wide. I don't know if this means you have duplicated the contents of a 1024-wide image to make a 2048-wide image.

无论如何,这里是我的建议。我们需要在实例变量中存储云层及其动画:

Anyway, here's what I suggest. We'll need to store the cloud layer and its animation in instance variables:

@implementation ViewController {
    CALayer *cloudLayer;
    CABasicAnimation *cloudLayerAnimation;
}

不是将云层的内容设置为云映像,颜色转换为从图像创建的图案颜色。这样,我们可以将图层的边界设置为任何我们想要的,图像将被平铺以填充边界:

Instead of setting the cloud layer's content to the cloud image, we set its background color to a pattern color created from the image. That way, we can set the layer's bounds to whatever we want and the image will be tiled to fill the bounds:

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

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

However, a CALayer's coordinate system puts the origin at the lower left instead of the upper left, with the Y axis increasing up. This means that the pattern will be drawn upside-down. We can fix that by flipping the Y axis:

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

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

By default, a layer's anchor point is at its center. This means that setting the layer's position sets the position of its center. It will be easier to position the layer by setting the position of its upper-left corner. We can do that by moving its anchor point to its upper-left corner:

    cloudLayer.anchorPoint = CGPointMake(0, 1);

图层的宽度必须是图片的宽度加上包含视图的宽度。这样,当我们滚动图层,使图像的右边缘进入视图,图像的另一个副本将绘制在第一个副本的右边。

The width of the layer needs to be the width of the image plus the width of the containing view. That way, as we scroll the layer so that the right edge of the image comes into view, another copy of the image will be drawn to the right of the first copy.

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

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

Now we're ready to add the layer to the view:

    [self.cloudsImageView.layer addSublayer:cloudLayer];

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

Now let's set up the animation. Remember that we changed the layer's anchor point, so we can control its position by setting the position of its upper-left corner. We want the layer's upper-left corner to start at the view's upper-left corner:

    CGPoint startPoint = CGPointZero;

,我们希望图层的左上角向左移动图片的宽度: p>

and we want the layer's upper-left corner to move left by the width of the image:

    CGPoint endPoint = CGPointMake(-cloudsImage.size.width, 0);

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

The rest of the animation setup is the same as your code. I changed the duration to 3 seconds for testing:

    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;

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

We'll call another method to actually attach the animation to the layer:

    [self applyCloudLayerAnimation];
}

这里是应用动画的方法:

Here's the method that applies the animation:

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

当应用程序进入后台(由于用户切换到另一个应用程序)系统从云层中删除动画。所以我们需要重新连接它,当我们再次进入前景。这就是为什么我们有 applyCloudLayerAnimation 方法。我们需要在应用程序进入前台时调用该方法。

When the application enters the background (because the user switched to another app), the system removes the animation from the cloud layer. So we need to reattach it when we enter the foreground again. That's why we have the applyCloudLayerAnimation method. We need to call that method when the app enters the foreground.

viewDidAppear:通知我们应用程序已进入前台:

In viewDidAppear:, we can start observing the notification that tells us the app has entered the foreground:

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

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

We need to stop observing the notification when our view disappears, or when the view controller is deallocated:

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

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

When the view controller actually receives the notification, we need to apply the animation again:

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

这里的所有代码一起便于复制和粘贴:

Here's all the code together for easy copy and paste:

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

这篇关于在无缝循环中动画无限滚动图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆