Вы говорите, что ваше изображение имеет ширину 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];
}