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