1. ホーム
  2. ios

[解決済み] 制約条件の変更をアニメーションで表現するには?

2022-03-21 13:56:55

質問

古いアプリをアップデートしているのですが、その際に AdBannerView で、広告がないときは画面外にスライドして表示されます。広告があるときは画面上にスライドします。基本的なことです。

旧来のスタイルでは、アニメーションブロックにフレームを設定します。 新スタイルでは IBOutlet を決定するオートレイアウトコンストレイントに変更します。 Y の位置、この場合はスーパービューの底面からの距離、そして定数を変更します。

- (void)moveBannerOffScreen {
    [UIView animateWithDuration:5 animations:^{
        _addBannerDistanceFromBottomConstraint.constant = -32;
    }];
    bannerIsVisible = FALSE;
}

- (void)moveBannerOnScreen {
    [UIView animateWithDuration:5 animations:^{
        _addBannerDistanceFromBottomConstraint.constant = 0;
    }];
    bannerIsVisible = TRUE;
}

そして、バナーは予想通り動きますが いいえ アニメーションを表示します。


UPDATEです。 再視聴しました WWDC 12講演 オートレイアウトを使いこなすためのベストプラクティス アニメーションを扱ったものです。を使用して制約を更新する方法について説明しています。 CoreAnimation :

以下のコードで試しましたが、まったく同じ結果になります。

- (void)moveBannerOffScreen {
    _addBannerDistanceFromBottomConstraint.constant = -32;
    [UIView animateWithDuration:2 animations:^{
        [self.view setNeedsLayout];
    }];
    bannerIsVisible = FALSE;
}

- (void)moveBannerOnScreen {
    _addBannerDistanceFromBottomConstraint.constant = 0;
    [UIView animateWithDuration:2 animations:^{
        [self.view setNeedsLayout];
    }];
    bannerIsVisible = TRUE;
}

余談ですが、何度も確認したところ、これが実行されているのは メイン スレッドになります。

解決方法は?

2つの重要な注意点

  1. を呼び出す必要があります。 layoutIfNeeded をアニメーションブロック内で使用します。 Apple では、保留中のレイアウト操作がすべて完了したことを確認するために、アニメーションブロックの前に一度このコマンドをコールすることを推奨しています。

  2. において具体的に呼び出す必要があります。 親ビュー (例. self.view であり、制約が付加されている子ビューではありません。 そうすることで すべて 制約を変更したビューに制約されている可能性のある他のビューのアニメーションを含む(例:ビューBがビューAの下部に取り付けられていて、ビューAの上部オフセットを変更し、ビューBを一緒にアニメーションさせたい場合など)。

これを試してみてください。

オブジェクティブC

- (void)moveBannerOffScreen {
    [self.view layoutIfNeeded];

    [UIView animateWithDuration:5
        animations:^{
            self._addBannerDistanceFromBottomConstraint.constant = -32;
            [self.view layoutIfNeeded]; // Called on parent view
        }];
    bannerIsVisible = FALSE;
}

- (void)moveBannerOnScreen { 
    [self.view layoutIfNeeded];

    [UIView animateWithDuration:5
        animations:^{
            self._addBannerDistanceFromBottomConstraint.constant = 0;
            [self.view layoutIfNeeded]; // Called on parent view
        }];
    bannerIsVisible = TRUE;
}

スウィフト3

UIView.animate(withDuration: 5) {
    self._addBannerDistanceFromBottomConstraint.constant = 0
    self.view.layoutIfNeeded()
}