如何使用 Core Animation 创建无限滚动循环
How to create an infinite scrolling loop with Core Animation
我是 apple 开发的新手,对 Core Animation 有疑问,据我了解,Core Animation 允许您使用对象/图像创建动画。
那里有多个教程,但它们都只是展示代码,并没有真正解释它是如何工作的。因此,当我尝试在我的应用程序中使用 Core Animation 时遇到了一些困难。
我的目标是使用可耕种图像创建永无止境的图像幻觉。我了解基本概念,我设置了 2 个 UIImageView,最初我尝试使用 NSTimer 每 0.01 秒调用 2 个方法来设置它们。一种方法是每次调用时将 Y 值加 1 来移动对象,另一种方法是每次调用时检查每个 UIImageView 的位置,然后当它到达允许它完全离开屏幕底部的像素时将其重置到顶部,不幸的是它非常滞后并且重置从未正常工作。
现在我转向了 Core Animation,因为我觉得这是创建移动对象的预期方式。我用我对它的最少知识来创建一些动画,但我尝试过的都没有真正奏效。
希望有人能帮我用两个 UIImageView 创造无限图像的错觉。我不介意你解释一下如何用 Core Animation 制作一个或者你是否想修复我写的原始代码的想法。
非常感谢任何帮助。
这是我制作的示例 UIViewController
。它使用基本的 UIView
实例而不是 UIImageView
,但那些应该是直接交换项目。
在我的测试中,效果是出现一个永无止境的红色和蓝色横幅(即从未见过视图控制器的白色背景)。
这 不 使用 CAAnimation
,而是利用为 UIView
提供的基于块的动画,我认为这更容易管理。
这是你想要的吗?
注意:这忽略了包含头文件ViewController.h
,但它完全没有任何代码。
// ViewController.m
#import "ViewController.h"
// Private Interface
@interface ViewController ()
#pragma mark -
#pragma mark - UI Controls
@property (strong, nonatomic) UIView *view1;
@property (strong, nonatomic) UIView *view2;
#pragma mark -
#pragma mark - Private Properties
@property (assign, nonatomic) BOOL isVisible;
@property (strong, nonatomic) NSLayoutConstraint *view1HeightConstraint;
@property (strong, nonatomic) NSLayoutConstraint *view2HeightConstraint;
@property (strong, nonatomic) NSLayoutConstraint *view1TopConstraint;
@property (strong, nonatomic) NSLayoutConstraint *view2TopConstraint;
@end
@implementation ViewController
#pragma mark -
#pragma mark - View Lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
[self setupUserInterface];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// At this point, self.view has its correct size,
// so use it to set the height of the sub views
self.view1HeightConstraint.constant = self.view.frame.size.height;
self.view2HeightConstraint.constant = self.view.frame.size.height;
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// The screen has been shown, so store this value and begin the animations
self.isVisible = YES;
[self slideDown1];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
// So that the animations will stop and this view controller can be released
self.isVisible = NO;
}
#pragma mark -
#pragma mark - Animations
- (void)slideDown1 {
// This sets the top of view1's frame equal to the bottom of self.view.frame
self.view1TopConstraint.constant = self.view.frame.size.height;
// This sets the top of view2's frame equal to the top of self.view.frame
self.view2TopConstraint.constant = 0.0f;
// If we didn't call this block, the changes set above would take effect "immediately"
[UIView animateWithDuration:1.0f
animations:^{
// Calling this inside of an animation causes the changes above to be animated
[self.view layoutIfNeeded];
}
completion:^(BOOL finished) {
// This block will execute when the animations finish
// This moves self.view1 so that its bottom is aligned with the top of self.view
self.view1TopConstraint.constant = -1.0f * self.view.frame.size.height;
// This causes the line above to take place immediately
[self.view layoutIfNeeded];
if (self.isVisible == YES) {
// If the screen is still visible, start the next animation
[self slideDown2];
}
}
];
}
- (void)slideDown2 {
self.view1TopConstraint.constant = 0.0f;
self.view2TopConstraint.constant = self.view.frame.size.height;
[UIView animateWithDuration:1.0f
animations:^{
[self.view layoutIfNeeded];
}
completion:^(BOOL finished) {
self.view2TopConstraint.constant = -1.0f * self.view.frame.size.height;
[self.view layoutIfNeeded];
if (self.isVisible == YES) {
[self slideDown1];
}
}
];
}
#pragma mark -
#pragma mark - UI Setup
- (void)setupUserInterface {
[self createControls];
[self setupControls];
[self layoutControls];
}
- (void)createControls {
self.view1 = [[UIView alloc] init];
self.view2 = [[UIView alloc] init];
}
- (void)setupControls {
self.view1.backgroundColor = [UIColor redColor];
// This line is required for our "full auto layout",
// which just means (in this case) that we're doing it all in code
[self.view1 setTranslatesAutoresizingMaskIntoConstraints:NO];
self.view2.backgroundColor = [UIColor blueColor];
[self.view2 setTranslatesAutoresizingMaskIntoConstraints:NO];
}
- (void)layoutControls {
// The subviews have to be added to self.view before we can constrain them
[self.view addSubview:self.view1];
[self.view addSubview:self.view2];
// This sets up the subviews to make their width equal to self.view's width
// You could have also used this method for the views' heights
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.view1
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeWidth
multiplier:1.0f
constant:0.0f]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.view2
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeWidth
multiplier:1.0f
constant:0.0f]];
// This gives us properties we can use later to animate the views' movements
self.view1TopConstraint = [NSLayoutConstraint constraintWithItem:self.view1
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeTop
multiplier:1.0f
constant:0.0f];
// You created the constraint, but it has to be installed/added
[self.view addConstraint:self.view1TopConstraint];
// A different and probably less effective way to set the heights of the subviews
self.view1HeightConstraint = [NSLayoutConstraint constraintWithItem:self.view1
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0f
constant:0.0f];
[self.view addConstraint:self.view1HeightConstraint];
self.view2TopConstraint = [NSLayoutConstraint constraintWithItem:self.view2
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeTop
multiplier:1.0f
constant:0.0f];
[self.view addConstraint:self.view2TopConstraint];
self.view2HeightConstraint = [NSLayoutConstraint constraintWithItem:self.view2
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0f
constant:0.0f];
[self.view addConstraint:self.view2HeightConstraint];
}
@end
我是 apple 开发的新手,对 Core Animation 有疑问,据我了解,Core Animation 允许您使用对象/图像创建动画。
那里有多个教程,但它们都只是展示代码,并没有真正解释它是如何工作的。因此,当我尝试在我的应用程序中使用 Core Animation 时遇到了一些困难。
我的目标是使用可耕种图像创建永无止境的图像幻觉。我了解基本概念,我设置了 2 个 UIImageView,最初我尝试使用 NSTimer 每 0.01 秒调用 2 个方法来设置它们。一种方法是每次调用时将 Y 值加 1 来移动对象,另一种方法是每次调用时检查每个 UIImageView 的位置,然后当它到达允许它完全离开屏幕底部的像素时将其重置到顶部,不幸的是它非常滞后并且重置从未正常工作。
现在我转向了 Core Animation,因为我觉得这是创建移动对象的预期方式。我用我对它的最少知识来创建一些动画,但我尝试过的都没有真正奏效。
希望有人能帮我用两个 UIImageView 创造无限图像的错觉。我不介意你解释一下如何用 Core Animation 制作一个或者你是否想修复我写的原始代码的想法。
非常感谢任何帮助。
这是我制作的示例 UIViewController
。它使用基本的 UIView
实例而不是 UIImageView
,但那些应该是直接交换项目。
在我的测试中,效果是出现一个永无止境的红色和蓝色横幅(即从未见过视图控制器的白色背景)。
这 不 使用 CAAnimation
,而是利用为 UIView
提供的基于块的动画,我认为这更容易管理。
这是你想要的吗?
注意:这忽略了包含头文件ViewController.h
,但它完全没有任何代码。
// ViewController.m
#import "ViewController.h"
// Private Interface
@interface ViewController ()
#pragma mark -
#pragma mark - UI Controls
@property (strong, nonatomic) UIView *view1;
@property (strong, nonatomic) UIView *view2;
#pragma mark -
#pragma mark - Private Properties
@property (assign, nonatomic) BOOL isVisible;
@property (strong, nonatomic) NSLayoutConstraint *view1HeightConstraint;
@property (strong, nonatomic) NSLayoutConstraint *view2HeightConstraint;
@property (strong, nonatomic) NSLayoutConstraint *view1TopConstraint;
@property (strong, nonatomic) NSLayoutConstraint *view2TopConstraint;
@end
@implementation ViewController
#pragma mark -
#pragma mark - View Lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
[self setupUserInterface];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// At this point, self.view has its correct size,
// so use it to set the height of the sub views
self.view1HeightConstraint.constant = self.view.frame.size.height;
self.view2HeightConstraint.constant = self.view.frame.size.height;
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// The screen has been shown, so store this value and begin the animations
self.isVisible = YES;
[self slideDown1];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
// So that the animations will stop and this view controller can be released
self.isVisible = NO;
}
#pragma mark -
#pragma mark - Animations
- (void)slideDown1 {
// This sets the top of view1's frame equal to the bottom of self.view.frame
self.view1TopConstraint.constant = self.view.frame.size.height;
// This sets the top of view2's frame equal to the top of self.view.frame
self.view2TopConstraint.constant = 0.0f;
// If we didn't call this block, the changes set above would take effect "immediately"
[UIView animateWithDuration:1.0f
animations:^{
// Calling this inside of an animation causes the changes above to be animated
[self.view layoutIfNeeded];
}
completion:^(BOOL finished) {
// This block will execute when the animations finish
// This moves self.view1 so that its bottom is aligned with the top of self.view
self.view1TopConstraint.constant = -1.0f * self.view.frame.size.height;
// This causes the line above to take place immediately
[self.view layoutIfNeeded];
if (self.isVisible == YES) {
// If the screen is still visible, start the next animation
[self slideDown2];
}
}
];
}
- (void)slideDown2 {
self.view1TopConstraint.constant = 0.0f;
self.view2TopConstraint.constant = self.view.frame.size.height;
[UIView animateWithDuration:1.0f
animations:^{
[self.view layoutIfNeeded];
}
completion:^(BOOL finished) {
self.view2TopConstraint.constant = -1.0f * self.view.frame.size.height;
[self.view layoutIfNeeded];
if (self.isVisible == YES) {
[self slideDown1];
}
}
];
}
#pragma mark -
#pragma mark - UI Setup
- (void)setupUserInterface {
[self createControls];
[self setupControls];
[self layoutControls];
}
- (void)createControls {
self.view1 = [[UIView alloc] init];
self.view2 = [[UIView alloc] init];
}
- (void)setupControls {
self.view1.backgroundColor = [UIColor redColor];
// This line is required for our "full auto layout",
// which just means (in this case) that we're doing it all in code
[self.view1 setTranslatesAutoresizingMaskIntoConstraints:NO];
self.view2.backgroundColor = [UIColor blueColor];
[self.view2 setTranslatesAutoresizingMaskIntoConstraints:NO];
}
- (void)layoutControls {
// The subviews have to be added to self.view before we can constrain them
[self.view addSubview:self.view1];
[self.view addSubview:self.view2];
// This sets up the subviews to make their width equal to self.view's width
// You could have also used this method for the views' heights
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.view1
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeWidth
multiplier:1.0f
constant:0.0f]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.view2
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeWidth
multiplier:1.0f
constant:0.0f]];
// This gives us properties we can use later to animate the views' movements
self.view1TopConstraint = [NSLayoutConstraint constraintWithItem:self.view1
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeTop
multiplier:1.0f
constant:0.0f];
// You created the constraint, but it has to be installed/added
[self.view addConstraint:self.view1TopConstraint];
// A different and probably less effective way to set the heights of the subviews
self.view1HeightConstraint = [NSLayoutConstraint constraintWithItem:self.view1
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0f
constant:0.0f];
[self.view addConstraint:self.view1HeightConstraint];
self.view2TopConstraint = [NSLayoutConstraint constraintWithItem:self.view2
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeTop
multiplier:1.0f
constant:0.0f];
[self.view addConstraint:self.view2TopConstraint];
self.view2HeightConstraint = [NSLayoutConstraint constraintWithItem:self.view2
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0f
constant:0.0f];
[self.view addConstraint:self.view2HeightConstraint];
}
@end