制約に変換しようとしているアニメーションがいくつかあります。その背後にある考え方は、エラーが発生したときにログイン プロンプトがバウンスするというものです。
私のアプローチは、ビュー コントローラーのすべてがメイン ビュー内にあるバウンス ビュー内にあるということです。
バウンスビューは、中央揃えの制約と先頭のスペースの制約を使用してメイン ビューに結び付けられます。設計時にレイアウトを明確にするために、先頭のスペースと上部のスペースの制約もあります。ただし、これらは単なるプレースホルダーであり、実行時に同じ高さ/幅の制約に置き換えられます。
メイン ビューに関連付けられているその他の制約はありません。
さて、いくつかの詳細…</p>
これらの制約を使用してバウンスを定義します。
enum {animationDone, bounceStart, bounceLeft, bounceRight, bounceReturn};
static const NSTimeInterval BounceDuration = 20.0;
static const int NumberOfBounces = 3;
static const CGFloat BounceDistance = 16.0f;
(通常、20 秒の遅延ははるかに短くなります。これが機能していないことを証明するために、遅延を増やしました。)
追加の実行時制約は次のように設定されます。
- (void)viewDidLoad {
[super viewDidLoad];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:_bounceView attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:_bounceView attribute:NSLayoutAttributeHeight multiplier:1.0 constant:0.0]];
}
次のコードでアニメーションを開始します。
_animateCount = NumberOfBounces;
_animateStage = bounceStart;
[self animationStep];
実際のコードは非常に単純です。
- (void)animationStep {
CGFloat bounceTo = 0;
BOOL half = NO;
switch (_animateStage) {
case bounceStart:
_animateStage = bounceLeft;
bounceTo = -BounceDistance;
half = YES;
break;
case bounceLeft:
_animateStage = bounceRight;
bounceTo = BounceDistance;
break;
case bounceRight:
if ( --_animateCount > 0 ) {
_animateStage = bounceLeft;
bounceTo = -BounceDistance;
} else {
_animateStage = bounceReturn;
bounceTo = 0;
}
break;
case bounceReturn:
half = YES;
_animateStage = animationDone;
break;
}
BOOL finishedAnimation = ( ( _animateStage == animationDone ) || ( self.view == nil ) );
if ( !finishedAnimation ) {
[_bounceView layoutIfNeeded];
_centerX.constant = bounceTo;
[_bounceView setNeedsUpdateConstraints];
NSTimeInterval duration = half ? BounceDuration / 2.0f : BounceDuration;
[UIView animateWithDuration:duration delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
NSLog(@"Bouncing to %f over %f seconds.", bounceTo, duration);
[_bounceView layoutIfNeeded];
} completion:^(BOOL finished) {
[self animationStep];
}];
}
}
ただし、これはすべて即座に完了します。
2013-10-29 10:59:43.852 App[9151:907] Bouncing to -16.000000 over 20.000000 seconds.
2013-10-29 10:59:43.864 App[9151:907] Bouncing to 16.000000 over 20.000000 seconds.
2013-10-29 10:59:43.865 App[9151:907] Bouncing to -16.000000 over 20.000000 seconds.
2013-10-29 10:59:43.866 App[9151:907] Bouncing to 16.000000 over 20.000000 seconds.
2013-10-29 10:59:43.866 App[9151:907] Bouncing to -16.000000 over 20.000000 seconds.
2013-10-29 10:59:43.867 App[9151:907] Bouncing to 16.000000 over 20.000000 seconds.
2013-10-29 10:59:43.867 App[9151:907] Bouncing to 0.000000 over 20.000000 seconds.
何か案は?
アップデート
後世の場合、これは呼び出しsetNeedsUpdateConstraints
とlayoutIfNeeded
子ビューで発生します。そうでないことを示唆するAppleのドキュメントにもかかわらず、スーパービューで呼び出す必要があります。これについては、以下の回答で詳しく説明しました。
ただし、代わりに @nielsbot の回答を受け入れました。私の質問に対する直接的な回答ではありませんが、私がやろうとしていたことを修正するよりも良い解決策です。