制約の変更をアニメーション化するにはどうすればよいですか?


959

古いアプリをで更新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;
}

バナーは予想通りに動きますがアニメーションはありません


更新:私はアニメーションをカバーする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;
}

余談ですが、私は何度もチェックしましたが、これはメインスレッドで実行されています。


11
私はこれまで、SOの誤植に対する質疑応答にこれほど多くの票が投じられるのを見たことがありませんでした
2013

3
回答にタイプミスがある場合は、回答を編集する必要があります。それが編集可能な理由です。
i_am_jorf 2014年

@jeffamaphone-タイプミスを指摘して、間違いがどこにあるのかわかったとしたら、もっと役に立ちます。あなたは自分で答えを編集し、タイプミスを修正して他のすべての人たちを救うことができます。参照していた場合は、アニメーションブロックから定数を削除するように編集しました。
DBD 2014年

1
タイプミスがわかりません。上記のコメントに対応していた。
i_am_jorf 2014年

9
次に、タイプミス問題です。ばかげて、「layoutIfNeeded」の代わりに「setNeedsLayout」と入力していた。エラーのあるコードと正しいコマンドのスクリーンショットをカットアンドペーストすると、質問にはっきりと表示されます。それでも、誰かが指摘するまで気付かなかったようです。
DBD

回答:


1697

2つの重要な注意事項:

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

  2. 制約が関連付けられている子ビューではなく、特に親ビュー(例:)で呼び出す必要self.viewがあります。そうすることで、制約を変更したビューに制約されている可能性のある他のビューのアニメーション化など、すべての制約されたビューが更新されます(たとえば、ビューBがビューAの下部にアタッチされ、ビューAの上部オフセットを変更しただけで、ビューBが必要な場合それでアニメートする)

これを試して:

Objective-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()
}

199
あなたは何を知っています...あなたの答えはうまくいきます。WWDCは機能します...私のビジョンは失敗します。どういうわけか、私がのsetNeedsLayout代わりに電話していることに気づくのに1週間かかりましたlayoutIfNeeded。間違ったメソッド名を入力しただけで気付かずに何時間も費やしたことに少し恐怖を感じます。
DBD、2012年

23
ソリューションは機能しますが、アニメーションブロック内で制約定数を変更する必要はありません。アニメーションを開始する前に、一度制約を設定するのはまったく問題ありません。回答を編集してください。
Ortwin Gentz 2013年

74
これは私にとって最初は機能しませんでしたが、制約が適用されるビューではなく、PARENTビューでlayoutIfNeededを呼び出す必要があることに気付きました。
Oliver Pearmain 2013年

20
layoutIfNeededを使用すると、制約の変更だけでなく、すべてのサブビューの更新がアニメーション化されます。制約の変更のみをアニメーション化するにはどうすればよいですか?
ngb 2013

11
「Appleは実際には、保留中のすべてのレイアウト操作が完了していることを確認するために、アニメーションブロックの前に一度呼び出すことをお勧めします。」
Rick van der Linde

109

私は提供された答えに感謝しますが、もう少しそれを取るといいと思います。

ドキュメントの基本的なブロックアニメーション

[containerView layoutIfNeeded]; // Ensures that all pending layout operations have been completed
[UIView animateWithDuration:1.0 animations:^{
     // Make all constraint changes here
     [containerView layoutIfNeeded]; // Forces the layout of the subtree animation block and then captures all of the frame changes
}];

しかし、これは非常に単純なシナリオです。updateConstraintsメソッドを介してサブビューの制約をアニメーション化したい場合はどうなり ますか?

サブビューのupdateConstraintsメソッドを呼び出すアニメーションブロック

[self.view layoutIfNeeded];
[self.subView setNeedsUpdateConstraints];
[self.subView updateConstraintsIfNeeded];
[UIView animateWithDuration:1.0f delay:0.0f options:UIViewAnimationOptionLayoutSubviews animations:^{
    [self.view layoutIfNeeded];
} completion:nil];

updateConstraintsメソッドはUIViewサブクラスでオーバーライドされ、メソッドの最後でスーパーを呼び出す必要があります。

- (void)updateConstraints
{
    // Update some constraints

    [super updateConstraints];
}

AutoLayoutガイドにまだ多くのことが求められていますが、一読する価値はあります。私自身、これをの一部として使用し、シンプルで微妙な折りたたみアニメーション(長さ0.2秒)のsのUISwitchペアでサブビューを切り替えUITextFieldます。サブビューの制約は、上記のようにUIViewサブクラスのupdateConstraintsメソッドで処理されます。


上記のすべてのメソッドをself.view(そのビューのサブビューでupdateConstraintsIfNeededはなく)呼び出す場合、呼び出す必要はありません(そのビューのsetNeedsLayoutトリガーも含まれるためupdateConstraints)。ほとんどの場合はささいなことかもしれませんが、今まで私にはありませんでした;)
anneblue 14

特定のケースでのAutolayoutとSprings and Strutsレイアウトの完全な相互作用を知らずにコメントするのは難しいです。私は純粋に自動レイアウトのシナリオについて完全に話しています。layoutSubviewsメソッドで正確に何が起こっているのか知りたいです。
Cameron Lowell Palmer、

translatesAutoresizingMaskIntoConstraints = NO; 純粋に自動レイアウトしたい場合は、これを必ず無効にしてください。
Cameron Lowell Palmer 14

私はそれを見たことはありませんが、コードなしでは問題を実際に話すことはできません。たぶん、あなたはTableViewをモックアップしてGitHubに貼り付けることができますか?
Cameron Lowell Palmer

申し訳ありませんが、私はgitHubを使用しません:(
anneblue '26

74

通常は、制約を更新しlayoutIfNeededてアニメーションブロック内で呼び出すだけです。これは、の.constantプロパティの変更、NSLayoutConstraint削除制約の追加(iOS 7)、または.active制約のプロパティの変更(iOS 8および9)のいずれかです。

サンプルコード:

[UIView animateWithDuration:0.3 animations:^{
    // Move to right
    self.leadingConstraint.active = false;
    self.trailingConstraint.active = true;

    // Move to bottom
    self.topConstraint.active = false;
    self.bottomConstraint.active = true;

    // Make the animation happen
    [self.view setNeedsLayout];
    [self.view layoutIfNeeded];
}];

サンプル設定:

Xcodeプロジェクトなので、サンプルアニメーションプロジェクト。

論争

アニメーションブロックのに、またはその内部で制約を変更する必要があるかどうかについていくつかの質問があります(以前の回答を参照)。

以下は、iOSを教えているMartin PilkingtonとAuto Layoutを書いたKen Ferryの間のTwitter会話です。ケンは、アニメーションブロックの外で定数を変更すると現在は機能する可能性がありますが、安全ではなく、アニメーションブロック内で実際に変更する必要があると説明しています。 https://twitter.com/kongtomorrow/status/440627401018466305

アニメーション:

サンプルプロジェクト

これは、ビューをアニメーション化する方法を示す簡単なプロジェクトです。Objective Cを使用しており.active、いくつかの制約のプロパティを変更してビューをアニメーション化します。 https://github.com/shepting/SampleAutoLayoutAnimation


+1は、新しいアクティブフラグを使用した例を示します。また、アニメーションブロックの外で制約を変更することは、常に私にとってハックのようなもの
Korey Hinton '24

このソリューションはビューを元の場所に戻すために機能しないため、githubで問題を提起しました。アクティブを変更することは正しい解決策ではないので、代わりに優先度を変更する必要があります。上部を750、下部を250に設定し、コードでUILayoutPriorityDefaultHighとUILayoutPriorityDefaultLowを交互に設定します。
Malhal

ブロック内で更新するもう1つの理由は、layoutIfNeededも呼び出す可能性のある呼び出しコードから変更を分離することです。(Twitterのリンクのためと感謝)
クリス・コノバー

1
すばらしい答えです。特に、これに関するマーティンとケンの会話に言及したからです。
ジョナ2017年

私は制約を更新する方法について混乱しており、これを書きました。見ていただけますか?
Honey

36
// Step 1, update your constraint
self.myOutletToConstraint.constant = 50; // New height (for example)

// Step 2, trigger animation
[UIView animateWithDuration:2.0 animations:^{

    // Step 3, call layoutIfNeeded on your animated view's parent
    [self.view layoutIfNeeded];
}];

29

Swift 4ソリューション

UIView.animate

3つの簡単なステップ:

  1. 制約を変更します。例:

    heightAnchor.constant = 50
  2. viewそのレイアウトがダーティであり、autolayoutがレイアウトを再計算する必要があることを含むを通知します。

    self.view.setNeedsLayout()
  3. アニメーションブロックで、レイアウトを再計算するようにレイアウトに指示します。これは、フレームを直接設定することと同じです(この場合、自動レイアウトはフレームを設定します)。

    UIView.animate(withDuration: 0.5) {
        self.view.layoutIfNeeded()
    }

最も簡単な例:

heightAnchor.constant = 50
self.view.setNeedsLayout()
UIView.animate(withDuration: 0.5) {
    self.view.layoutIfNeeded()
}

サイドノート

オプションの0番目のステップがあります-制約を変更する前self.view.layoutIfNeeded()に、アニメーションの開始点が古い制約が適用された状態であることを確認するために呼び出すことができます(アニメーションに含めるべきでない他の制約の変更があった場合) ):

otherConstraint.constant = 30
// this will make sure that otherConstraint won't be animated but will take effect immediately
self.view.layoutIfNeeded()

heightAnchor.constant = 50
self.view.setNeedsLayout()
UIView.animate(withDuration: 0.5) {
    self.view.layoutIfNeeded()
}

UIViewPropertyAnimator

iOS 10では新しいアニメーションメカニズムが追加UIViewPropertyAnimatorされたので、基本的に同じメカニズムがそれに適用されることを知っておく必要があります。手順は基本的に同じです:

heightAnchor.constant = 50
self.view.setNeedsLayout()
let animator = UIViewPropertyAnimator(duration: 0.5, timingParameters: UICubicTimingParameters(animationCurve: .linear))
animator.addAnimations {
    self.view.layoutIfNeeded()
}
animator.startAnimation()

animatorはアニメーションのカプセル化なので、参照を維持して後で呼び出すことができます。ただし、アニメーションブロックでは、自動レイアウトにフレームを再計算するように指示するだけなので、を呼び出す前に制約を変更する必要がありますstartAnimation。したがって、次のようなことが可能です。

// prepare the animator first and keep a reference to it
let animator = UIViewPropertyAnimator(duration: 0.5, timingParameters: UICubicTimingParameters(animationCurve: .linear))
animator.addAnimations {
    self.view.layoutIfNeeded()
}

// at some other point in time we change the constraints and call the animator
heightAnchor.constant = 50
self.view.setNeedsLayout()
animator.startAnimation()

制約の変更とアニメーターの開始の順序は重要です。制約を変更し、アニメーターを後の時点に残すと、次の再描画サイクルで自動レイアウト再計算が呼び出され、変更はアニメートされません。

また、1つのアニメーターは再利用できないことを忘れないでください。一度実行すると、「再実行」することはできません。したがって、インタラクティブアニメーションを制御するために使用しない限り、アニメーターをそのままにしておく十分な理由はないと思います。


swSwift 5でも動作します
spnkr

layoutIfNeeded()が鍵
Medhi

15

ストーリーボード、コード、ヒント、およびいくつかの注意点

他の答えは問題ありませんが、これは最近の例を使用して制約をアニメーション化することのいくつかのかなり重要な問題を強調しています。次のことに気付く前に、さまざまなバリエーションを試しました。

強力な参照を保持するために、対象とする制約をクラス変数に作成します。Swiftでは遅延変数を使用しました:

lazy var centerYInflection:NSLayoutConstraint = {
       let temp =  self.view.constraints.filter({ $0.firstItem is MNGStarRating }).filter ( { $0.secondItem is UIWebView }).filter({ $0.firstAttribute == .CenterY }).first
        return temp!
}()

いくつかの実験の後、私は、1つのビューからの制約を取得しなければならないことに留意ABOVE(スーパー別名)制約が定義されている二つのビュー。以下の例では(MNGStarRatingとUIWebViewの両方が、私が間に制約を作成する2つのタイプのアイテムであり、それらはself.view内のサブビューです)。

フィルターチェーン

Swiftのフィルターメソッドを利用して、変曲点として機能する必要な制約を分離します。さらに複雑になる可能性もありますが、ここではフィルターが適切に機能します。

Swiftを使用して制約をアニメーション化する

Nota Bene-この例はストーリーボード/コードソリューションであり、ストーリーボードにデフォルトの制約が設定されていることを前提としています。次に、コードを使用して変更をアニメーション化できます。

正確な基準でフィルタリングするプロパティを作成し、アニメーションの特定の変曲点に到達すると仮定します(もちろん、配列をフィルタリングして、複数の制約が必要な場合はループすることもできます)。

lazy var centerYInflection:NSLayoutConstraint = {
    let temp =  self.view.constraints.filter({ $0.firstItem is MNGStarRating }).filter ( { $0.secondItem is UIWebView }).filter({ $0.firstAttribute == .CenterY }).first
    return temp!
}()

....

今度いつか...

@IBAction func toggleRatingView (sender:AnyObject){

    let aPointAboveScene = -(max(UIScreen.mainScreen().bounds.width,UIScreen.mainScreen().bounds.height) * 2.0)

    self.view.layoutIfNeeded()


    //Use any animation you want, I like the bounce in springVelocity...
    UIView.animateWithDuration(1.0, delay: 0.0, usingSpringWithDamping: 0.3, initialSpringVelocity: 0.75, options: [.CurveEaseOut], animations: { () -> Void in

        //I use the frames to determine if the view is on-screen
        if CGRectContainsRect(self.view.frame, self.ratingView.frame) {

            //in frame ~ animate away
            //I play a sound to give the animation some life

            self.centerYInflection.constant = aPointAboveScene
            self.centerYInflection.priority = UILayoutPriority(950)

        } else {

            //I play a different sound just to keep the user engaged
            //out of frame ~ animate into scene
            self.centerYInflection.constant = 0
            self.centerYInflection.priority = UILayoutPriority(950)
            self.view.setNeedsLayout()
            self.view.layoutIfNeeded()
         }) { (success) -> Void in

            //do something else

        }
    }
}

多くの間違ったターン

これらのメモは、実際に私が自分のために書いた一連のヒントです。私はすべてのことを個人的にそして辛抱強く行いました。うまくいけば、このガイドは他の人を救うことができます。

  1. zPositioningに注意してください。明らかに何も起こっていない場合は、他のビューの一部を非表示にするか、ビューデバッガーを使用してアニメーションビューを見つける必要があります。ストーリーボードのxmlでユーザー定義のランタイム属性が失われ、アニメーションビューが(作業中に)カバーされる場合さえありました。

  2. ドキュメント(新旧)、クイックヘルプ、およびヘッダーを読むのに常に1分かかります。AppleはAutoLayout制約をより適切に管理するために多くの変更を続けています(スタックビューを参照)。または、少なくともAutoLayoutクックブック。時々、最良の解決策は古いドキュメント/ビデオにあることを覚えておいてください。

  3. アニメーションの値をいじって、他のanimateWithDurationバリアントの使用を検討してください。

  4. 特定のレイアウト値を他の定数への変更を決定する基準としてハードコーディングしないでください。代わりに、ビューの場所を決定できる値を使用してください。CGRectContainsRect一例です

  5. 必要に応じて、制約定義に参加しているビューに関連付けられているレイアウトマージンを使用することをためらわないでください let viewMargins = self.webview.layoutMarginsGuide:例にあります
  6. 必要のない作業は行わないでください。ストーリーボードに制約があるすべてのビューには、プロパティself.viewName.constraintsに制約がアタッチされています。
  7. 制約の優先度を1000未満に変更します。ストーリーボードで、鉱山を250(低)または750(高)に設定しました。(1000の優先度をコード内の何かに変更しようとすると、1000が必要なため、アプリがクラッシュします)
  8. activateConstraintsとdeactivateConstraintsをすぐに使用しようとしないことを検討してください(それらには場所がありますが、学習している場合、またはこれらを使用してストーリーボードを使用している場合は、多すぎることを意味します〜以下に示すように場所があります)
  9. コードに新しい制約を実際に追加するのでない限り、addConstraints / removeConstraintsを使用しないことを検討してください。ほとんどの場合、ストーリーボードのビューを目的の制約でレイアウトし(ビューを画面外に配置)、コードで、以前にストーリーボードで作成した制約をアニメーション化してビューを移動します。
  10. 新しいNSAnchorLayoutクラスとサブクラスを使用して制約を構築するのに多くの時間を費やしました。これらは問題なく機能しますが、必要なすべての制約がストーリーボードにすでに存在していることを理解するのにしばらく時間がかかりました。コードで制約を作成する場合、このメソッドを使用して制約を集計するのが最も確実です。

ストーリーボード使用時の回避策の簡単なサンプル

private var _nc:[NSLayoutConstraint] = []
    lazy var newConstraints:[NSLayoutConstraint] = {

        if !(self._nc.isEmpty) {
            return self._nc
        }

        let viewMargins = self.webview.layoutMarginsGuide
        let minimumScreenWidth = min(UIScreen.mainScreen().bounds.width,UIScreen.mainScreen().bounds.height)

        let centerY = self.ratingView.centerYAnchor.constraintEqualToAnchor(self.webview.centerYAnchor)
        centerY.constant = -1000.0
        centerY.priority = (950)
        let centerX =  self.ratingView.centerXAnchor.constraintEqualToAnchor(self.webview.centerXAnchor)
        centerX.priority = (950)

        if let buttonConstraints = self.originalRatingViewConstraints?.filter({

            ($0.firstItem is UIButton || $0.secondItem is UIButton )
        }) {
            self._nc.appendContentsOf(buttonConstraints)

        }

        self._nc.append( centerY)
        self._nc.append( centerX)

        self._nc.append (self.ratingView.leadingAnchor.constraintEqualToAnchor(viewMargins.leadingAnchor, constant: 10.0))
        self._nc.append (self.ratingView.trailingAnchor.constraintEqualToAnchor(viewMargins.trailingAnchor, constant: 10.0))
        self._nc.append (self.ratingView.widthAnchor.constraintEqualToConstant((minimumScreenWidth - 20.0)))
        self._nc.append (self.ratingView.heightAnchor.constraintEqualToConstant(200.0))

        return self._nc
    }()

これらのヒントの1つ、またはlayoutIfNeededを追加する場所などのより単純なヒントの1つを忘れた場合、ほとんど何も起こりません。その場合、次のような中途半端な解決策が考えられます。

注意-以下のAutoLayoutセクションと元のガイドをお読みください。これらのテクニックを使用してダイナミックアニメーターを補足する方法があります。

UIView.animateWithDuration(1.0, delay: 0.0, usingSpringWithDamping: 0.3, initialSpringVelocity: 1.0, options: [.CurveEaseOut], animations: { () -> Void in

            //
            if self.starTopInflectionPoint.constant < 0  {
                //-3000
                //offscreen
                self.starTopInflectionPoint.constant = self.navigationController?.navigationBar.bounds.height ?? 0
                self.changeConstraintPriority([self.starTopInflectionPoint], value: UILayoutPriority(950), forView: self.ratingView)

            } else {

                self.starTopInflectionPoint.constant = -3000
                 self.changeConstraintPriority([self.starTopInflectionPoint], value: UILayoutPriority(950), forView: self.ratingView)
            }

        }) { (success) -> Void in

            //do something else
        }

    }

AutoLayoutガイドのスニペット(2番目のスニペットはOS Xを使用するためのものです)。ところで-私が見る限り、これは現在のガイドにはもうありません。 推奨される手法は進化し続けています。

自動レイアウトによる変更のアニメーション化

自動レイアウトによるアニメーションの変更を完全に制御する必要がある場合は、プログラムで制約を変更する必要があります。基本的な概念はiOSとOS Xの両方で同じですが、いくつかの小さな違いがあります。

iOSアプリでは、コードは次のようになります。

[containerView layoutIfNeeded]; // Ensures that all pending layout operations have been completed
[UIView animateWithDuration:1.0 animations:^{
     // Make all constraint changes here
     [containerView layoutIfNeeded]; // Forces the layout of the subtree animation block and then captures all of the frame changes
}];

OS Xでは、レイヤーベースのアニメーションを使用するときに次のコードを使用します。

[containterView layoutSubtreeIfNeeded];
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
     [context setAllowsImplicitAnimation: YES];
     // Make all constraint changes here
     [containerView layoutSubtreeIfNeeded];
}];

レイヤーベースのアニメーションを使用していない場合は、コンストレイントのアニメーターを使用して定数をアニメーション化する必要があります。

[[constraint animator] setConstant:42];

よりよく視覚的に学ぶ人のために、アップルからこの初期のビデオをチェックしてください

注意を払う

ドキュメントには、大きなアイデアにつながる小さなメモやコードが含まれていることがよくあります。たとえば、自動レイアウト制約をダイナミックアニメーターにアタッチすることは、素晴らしいアイデアです。

幸運とフォースがあなたと共におられますように。



7

ワーキングソリューション100% Swift 3.1

私はすべての答えを読んだ後、すべてのアプリケーションで正しくアニメーション化するために使用したコードと行の階層を共有したいと思っています。

self.view.layoutIfNeeded() // Force lays of all subviews on root view
UIView.animate(withDuration: 0.5) { [weak self] in // allowing to ARC to deallocate it properly
       self?.tbConstraint.constant = 158 // my constraint constant change
       self?.view.layoutIfNeeded() // Force lays of all subviews on root view again.
}

4

私は制約をアニメーション化しようとしていて、良い説明を見つけるのは本当に簡単ではありませんでした。

他にどのような答えが言っていることは全く真実である:あなたが呼び出す必要があり[self.view layoutIfNeeded];内部 animateWithDuration: animations:。ただし、他の重要なポイントはNSLayoutConstraint、アニメーション化するすべてのオブジェクトにポインタを置くことです。

GitHubで例を作成しました


4

Xcode 8.3.3を使用したSwift 3の実際にテストされたソリューション:

self.view.layoutIfNeeded()
self.calendarViewHeight.constant = 56.0

UIView.animate(withDuration: 0.5, delay: 0.0, options: UIViewAnimationOptions.curveEaseIn, animations: {
        self.view.layoutIfNeeded()
    }, completion: nil)

self.calendarViewHeightは、customView(CalendarView)を参照する制約であることを覚えておいてください。self.calendarViewではなく、self.viewで.layoutIfNeeded()を呼び出しました

この助けを願っています。


3

これについての記事の話がありますhttp : //weblog.invasivecode.com/post/42362079291/auto-layout-and-core-animation-auto-layout-was

その中で、彼は次のようにコーディングしました:

- (void)handleTapFrom:(UIGestureRecognizer *)gesture {
    if (_isVisible) {
        _isVisible = NO;
        self.topConstraint.constant = -44.;    // 1
        [self.navbar setNeedsUpdateConstraints];  // 2
        [UIView animateWithDuration:.3 animations:^{
            [self.navbar layoutIfNeeded]; // 3
        }];
    } else {
        _isVisible = YES;
        self.topConstraint.constant = 0.;
        [self.navbar setNeedsUpdateConstraints];
        [UIView animateWithDuration:.3 animations:^{
            [self.navbar layoutIfNeeded];
        }];
    }
}

それが役に立てば幸い。


1

制約アニメーションのコンテキストでは、keyboard_opened通知内で制約をすぐにアニメーション化した特定の状況について触れたいと思います。

制約により、テキストフィールドからコンテナの上部までの上部スペースが定義されました。キーボードを開いたら、定数を2で割ります。

キーボード通知内で一貫したスムーズな制約アニメーションを直接実現することができませんでした。ビューの約半分は、アニメーション化せずに、新しい位置にジャンプするだけです。

キーボードを開いた結果、追加のレイアウトが発生している可能性があります。10msの遅延を持つ単純なdispatch_afterブロックを追加すると、アニメーションが毎回実行されます-ジャンプしません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.