如何在IOS中一个一个地动画约束?
How to animate constraints one by one in IOS?
我有 6 个观点。我想一个一个地为约束设置动画,即,我只需要在第一个视图之后的第二个视图上播放动画,然后是第二个视图之后的第三个视图,依此类推。我已经在动画的完成处理程序中添加了代码,但它不起作用。所有约束的初始值在故事板中设置为 300。我想一个一个的改成0。现在,只有第一个动画在工作。这就是我所做的。
layoutTopFirst.constant = 0.0;
[UIView animateWithDuration:1.0 animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
self->layoutTopSecond.constant = 0.0;
[UIView animateWithDuration:1.0 animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
self->layoutTopThird.constant = 0.0;
[UIView animateWithDuration:1.0 animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
self->layoutTopFourth.constant = 0.0;
[UIView animateWithDuration:1.0 animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
self->layoutTopFifth.constant = 0.0;
[UIView animateWithDuration:1.0 animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
self->layoutTopSixth.constant = 0.0;
[UIView animateWithDuration:1.0 animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
}];
}];
}];
}];
}];
}];
如何一个接一个地做动画?
如果您显示所有代码(如何设置约束等),将会有所帮助。
但是,这是一个简单的例子。
它创建 6 个标签,顶部约束为 100。点击“执行动画”按钮将它们动画化到顶部:0.0 ...再次点击动画回到 100:
#import "SequentialAnimViewController.h"
@interface SequentialAnimViewController () {
NSMutableArray *views;
NSMutableArray *topConstraints;
}
@end
@implementation SequentialAnimViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
[button addTarget:self action:@selector(animViews) forControlEvents:UIControlEventTouchUpInside];
[button setTitle:@"Do Anim" forState:UIControlStateNormal];
button.backgroundColor = [UIColor colorWithWhite:0.9 alpha:1.0];
button.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:button];
[button.centerXAnchor constraintEqualToAnchor:[self.view centerXAnchor]].active = YES;
[button.centerYAnchor constraintEqualToAnchor:[self.view centerYAnchor]].active = YES;
[button.widthAnchor constraintEqualToConstant:200.0].active = YES;
views = [NSMutableArray new];
topConstraints = [NSMutableArray new];
CGFloat x = 40.0;
CGFloat w = 40.0;
UILayoutGuide *g = [self.view safeAreaLayoutGuide];
for (int i = 0; i < 6; i++) {
UILabel *v = [UILabel new];
v.backgroundColor = [UIColor blueColor];
v.textColor = [UIColor yellowColor];
v.textAlignment = NSTextAlignmentCenter;
v.text = [NSString stringWithFormat:@"%i", i];
v.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:v];
[v.widthAnchor constraintEqualToConstant:w].active = YES;
[v.heightAnchor constraintEqualToConstant:w].active = YES;
[v.leadingAnchor constraintEqualToAnchor:g.leadingAnchor constant:x].active = YES;
[topConstraints addObject:[v.topAnchor constraintEqualToAnchor:g.topAnchor constant:100.0]];
[views addObject:v];
x += w + 8;
}
[NSLayoutConstraint activateConstraints:topConstraints];
}
-(void)animViews {
__block int i = 0;
__block CGFloat newConstant = ((NSLayoutConstraint *)self->topConstraints[0]).constant == 0.0 ? 100.0 : 0.0;
((NSLayoutConstraint *)self->topConstraints[i++]).constant = newConstant;
[UIView animateWithDuration:1.0 animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
((NSLayoutConstraint *)self->topConstraints[i++]).constant = newConstant;
[UIView animateWithDuration:1.0 animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
((NSLayoutConstraint *)self->topConstraints[i++]).constant = newConstant;
[UIView animateWithDuration:1.0 animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
((NSLayoutConstraint *)self->topConstraints[i++]).constant = newConstant;
[UIView animateWithDuration:1.0 animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
((NSLayoutConstraint *)self->topConstraints[i++]).constant = newConstant;
[UIView animateWithDuration:1.0 animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
((NSLayoutConstraint *)self->topConstraints[i++]).constant = newConstant;
[UIView animateWithDuration:1.0 animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
NSLog(@"All Done!");
}];
}];
}];
}];
}];
}];
}
@end
如果只有第一个动画,请确保
- 您的其他五个约束引用都指向不同的垂直约束...例如,如果它们是
nil
,您将看不到任何变化;
- 他们都是
isActive
;
- 没有任何其他约束阻止更新的常量产生变化。
对于它的价值,您可以考虑使用关键帧动画消除完成处理程序塔,例如
CGFloat relativeDuration = 1.0 / 6.0;
[UIView animateKeyframesWithDuration:6 delay:0 options:kNilOptions animations:^{
[UIView addKeyframeWithRelativeStartTime:0 relativeDuration:relativeDuration animations:^{
self.topConstraint1.constant = 0;
[self.view layoutIfNeeded];
}];
[UIView addKeyframeWithRelativeStartTime:1.0 * relativeDuration relativeDuration:relativeDuration animations:^{
self.topConstraint2.constant = 0;
[self.view layoutIfNeeded];
}];
[UIView addKeyframeWithRelativeStartTime:2.0 * relativeDuration relativeDuration:relativeDuration animations:^{
self.topConstraint3.constant = 0;
[self.view layoutIfNeeded];
}];
[UIView addKeyframeWithRelativeStartTime:3.0 * relativeDuration relativeDuration:relativeDuration animations:^{
self.topConstraint4.constant = 0;
[self.view layoutIfNeeded];
}];
[UIView addKeyframeWithRelativeStartTime:4.0 * relativeDuration relativeDuration:relativeDuration animations:^{
self.topConstraint5.constant = 0;
[self.view layoutIfNeeded];
}];
[UIView addKeyframeWithRelativeStartTime:5.0 * relativeDuration relativeDuration:relativeDuration animations:^{
self.topConstraint6.constant = 0;
[self.view layoutIfNeeded];
}];
} completion:nil];
或者,更简单:
NSArray <NSLayoutConstraint *> *constraints = @[self.topConstraint1, self.topConstraint2, self.topConstraint3, self.topConstraint4, self.topConstraint5, self.topConstraint6];
CGFloat relativeDuration = 1.0 / (CGFloat) constraints.count;
[UIView animateKeyframesWithDuration:totalDuration delay:0 options:kNilOptions animations:^{
for (NSInteger i = 0; i < constraints.count; i++) {
[UIView addKeyframeWithRelativeStartTime: ((CGFloat) i) * relativeDuration relativeDuration:relativeDuration animations:^{
constraints[i].constant = 0;
[self.view layoutIfNeeded];
}];
}
} completion:nil];
产量:
我有 6 个观点。我想一个一个地为约束设置动画,即,我只需要在第一个视图之后的第二个视图上播放动画,然后是第二个视图之后的第三个视图,依此类推。我已经在动画的完成处理程序中添加了代码,但它不起作用。所有约束的初始值在故事板中设置为 300。我想一个一个的改成0。现在,只有第一个动画在工作。这就是我所做的。
layoutTopFirst.constant = 0.0;
[UIView animateWithDuration:1.0 animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
self->layoutTopSecond.constant = 0.0;
[UIView animateWithDuration:1.0 animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
self->layoutTopThird.constant = 0.0;
[UIView animateWithDuration:1.0 animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
self->layoutTopFourth.constant = 0.0;
[UIView animateWithDuration:1.0 animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
self->layoutTopFifth.constant = 0.0;
[UIView animateWithDuration:1.0 animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
self->layoutTopSixth.constant = 0.0;
[UIView animateWithDuration:1.0 animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
}];
}];
}];
}];
}];
}];
如何一个接一个地做动画?
如果您显示所有代码(如何设置约束等),将会有所帮助。
但是,这是一个简单的例子。
它创建 6 个标签,顶部约束为 100。点击“执行动画”按钮将它们动画化到顶部:0.0 ...再次点击动画回到 100:
#import "SequentialAnimViewController.h"
@interface SequentialAnimViewController () {
NSMutableArray *views;
NSMutableArray *topConstraints;
}
@end
@implementation SequentialAnimViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
[button addTarget:self action:@selector(animViews) forControlEvents:UIControlEventTouchUpInside];
[button setTitle:@"Do Anim" forState:UIControlStateNormal];
button.backgroundColor = [UIColor colorWithWhite:0.9 alpha:1.0];
button.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:button];
[button.centerXAnchor constraintEqualToAnchor:[self.view centerXAnchor]].active = YES;
[button.centerYAnchor constraintEqualToAnchor:[self.view centerYAnchor]].active = YES;
[button.widthAnchor constraintEqualToConstant:200.0].active = YES;
views = [NSMutableArray new];
topConstraints = [NSMutableArray new];
CGFloat x = 40.0;
CGFloat w = 40.0;
UILayoutGuide *g = [self.view safeAreaLayoutGuide];
for (int i = 0; i < 6; i++) {
UILabel *v = [UILabel new];
v.backgroundColor = [UIColor blueColor];
v.textColor = [UIColor yellowColor];
v.textAlignment = NSTextAlignmentCenter;
v.text = [NSString stringWithFormat:@"%i", i];
v.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:v];
[v.widthAnchor constraintEqualToConstant:w].active = YES;
[v.heightAnchor constraintEqualToConstant:w].active = YES;
[v.leadingAnchor constraintEqualToAnchor:g.leadingAnchor constant:x].active = YES;
[topConstraints addObject:[v.topAnchor constraintEqualToAnchor:g.topAnchor constant:100.0]];
[views addObject:v];
x += w + 8;
}
[NSLayoutConstraint activateConstraints:topConstraints];
}
-(void)animViews {
__block int i = 0;
__block CGFloat newConstant = ((NSLayoutConstraint *)self->topConstraints[0]).constant == 0.0 ? 100.0 : 0.0;
((NSLayoutConstraint *)self->topConstraints[i++]).constant = newConstant;
[UIView animateWithDuration:1.0 animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
((NSLayoutConstraint *)self->topConstraints[i++]).constant = newConstant;
[UIView animateWithDuration:1.0 animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
((NSLayoutConstraint *)self->topConstraints[i++]).constant = newConstant;
[UIView animateWithDuration:1.0 animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
((NSLayoutConstraint *)self->topConstraints[i++]).constant = newConstant;
[UIView animateWithDuration:1.0 animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
((NSLayoutConstraint *)self->topConstraints[i++]).constant = newConstant;
[UIView animateWithDuration:1.0 animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
((NSLayoutConstraint *)self->topConstraints[i++]).constant = newConstant;
[UIView animateWithDuration:1.0 animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
NSLog(@"All Done!");
}];
}];
}];
}];
}];
}];
}
@end
如果只有第一个动画,请确保
- 您的其他五个约束引用都指向不同的垂直约束...例如,如果它们是
nil
,您将看不到任何变化; - 他们都是
isActive
; - 没有任何其他约束阻止更新的常量产生变化。
对于它的价值,您可以考虑使用关键帧动画消除完成处理程序塔,例如
CGFloat relativeDuration = 1.0 / 6.0;
[UIView animateKeyframesWithDuration:6 delay:0 options:kNilOptions animations:^{
[UIView addKeyframeWithRelativeStartTime:0 relativeDuration:relativeDuration animations:^{
self.topConstraint1.constant = 0;
[self.view layoutIfNeeded];
}];
[UIView addKeyframeWithRelativeStartTime:1.0 * relativeDuration relativeDuration:relativeDuration animations:^{
self.topConstraint2.constant = 0;
[self.view layoutIfNeeded];
}];
[UIView addKeyframeWithRelativeStartTime:2.0 * relativeDuration relativeDuration:relativeDuration animations:^{
self.topConstraint3.constant = 0;
[self.view layoutIfNeeded];
}];
[UIView addKeyframeWithRelativeStartTime:3.0 * relativeDuration relativeDuration:relativeDuration animations:^{
self.topConstraint4.constant = 0;
[self.view layoutIfNeeded];
}];
[UIView addKeyframeWithRelativeStartTime:4.0 * relativeDuration relativeDuration:relativeDuration animations:^{
self.topConstraint5.constant = 0;
[self.view layoutIfNeeded];
}];
[UIView addKeyframeWithRelativeStartTime:5.0 * relativeDuration relativeDuration:relativeDuration animations:^{
self.topConstraint6.constant = 0;
[self.view layoutIfNeeded];
}];
} completion:nil];
或者,更简单:
NSArray <NSLayoutConstraint *> *constraints = @[self.topConstraint1, self.topConstraint2, self.topConstraint3, self.topConstraint4, self.topConstraint5, self.topConstraint6];
CGFloat relativeDuration = 1.0 / (CGFloat) constraints.count;
[UIView animateKeyframesWithDuration:totalDuration delay:0 options:kNilOptions animations:^{
for (NSInteger i = 0; i < constraints.count; i++) {
[UIView addKeyframeWithRelativeStartTime: ((CGFloat) i) * relativeDuration relativeDuration:relativeDuration animations:^{
constraints[i].constant = 0;
[self.view layoutIfNeeded];
}];
}
} completion:nil];
产量: