半径が変化する円を描画するUIViewサブクラスがあります(ニースの弾力性のあるアニメーションを使用)。ビューは円のサイズを決定しています。
このUIViewサブクラスのフレームサイズを変更して、円の半径のアニメーションによる変更に一致させ、ビューに接続されているNSLayoutConstraintsを変更します(円のエッジに制約されているビューがサークルのサイズが変更されます)。
半径が変更されたときに-(CGSize)intrinsicContentSize
を実装してinvalidateIntrinsicContentSize
を呼び出すと、制約に更新が指示されることを理解していますが、intrinsicContentSize
への変更をアニメーション化する方法がわかりません。
[UIView animateWith ...ブロック内からinvalidateIntrinsicContentSize
を呼び出すと、レイアウトが即座に更新されます。
これは可能ですか、回避策/より良いアプローチはありますか?
invalidateIntrinsicContentSize
は、アニメーションやlayoutIfNeeded
でうまく機能します。考慮すべき唯一のことは、固有のコンテンツサイズを変更すると、スーパービューのレイアウトが無効になることです。だからこれはうまくいくはずです:
[UIView animateWithDuration:0.2 animations:^{
[self invalidateIntrinsicContentSize];
[self.superview setNeedsLayout];
[self.superview layoutIfNeeded];
}];
幅/高さの制約は役に立ちませんか?この制約の参照を維持し、...
_[NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:myViewInitialWidth];
_
... myViewのサイズ変更をアニメーション化する場合は、次のようにします...
_self.viewWidthConstraint.constant = 100; // new width
[UIView animateWithDuration:0.3 animations:^{ [view layoutIfNeeded]; }];
_
高さについても同じことを行います。
他の制約によって異なりますが、これらの2つの制約の優先順位を上げる必要があるかもしれません。
または、UIView
をサブクラス化し、- (void)invalidateIntrinsicContentSize:(BOOL)animated
を追加して、自分で偽造することもできます。 - (CGSize)intrinsicContentSize
から新しいサイズを取得し、幅/高さの制約をアニメーション化してアニメーション化します。または、プロパティを追加してアニメーションを有効/無効にし、invalidateIntrinsicContentSize
をオーバーライドして、このメソッド内で実行します。たくさんの方法 ...
Swift私のために働いた@stigiの回答のバージョン:
UIView.animate(withDuration: 0.2, animations: {
self.invalidateIntrinsicContentSize()
self.superview?.setNeedsLayout()
self.superview?.layoutIfNeeded()
})
以下のコードでは、組み込みクラスは、変数を変更するとサイズが変更されたクラスです。組み込みクラスをアニメーション化するには、以下のコードのみを使用してください。ビュー階層の上位にある他のオブジェクトに影響を与える場合は、self.intrinsicクラスをsetNeedsLayoutおよびlayoutIfNeededの最上位のビューに置き換えます。
[UIView animateWithDuration:.2 animations:^{
self.intrinsicClass.numberOfWeeks=8;
[self.intrinsicClass setNeedsLayout];
[self.intrinsicClass layoutIfNeeded];
}];
これのどれも私のために働いていません。 NSAttributedStringで設定しているUILabelがあります。テキストは複数行で、Wordの境界で折り返されます。したがって、高さは可変です。私はこれを試しました:
[UIView animateWithDuration:1.0f animations:^{
self.label = newLabelText;
[self.label invalidateIntrinsicContentSize];
[self.view setNeedsLayout];
[self.view layoutIfNeeded];
}];
そして、いくつかのバリエーション。何も動作しません。ラベルはすぐにサイズを変更し、新しい位置にスライドします。したがって、画面上のラベル位置のアニメーションが機能しています。しかし、ラベルのサイズ変更のアニメーションはそうではありません。
Swift 4/3の場合はこれでうまくいきます。これがベストプラクティスだと思います。UILabelが含まれているUIViewがあり、UIViewがUILabelのフレームを適応させる場合は、次を使用します。
self.theUILabel.text = "text update"
UIView.animate(withDuration: 5.0, animations: {
self.theUIView.layoutIfNeeded()
})
通常のself.view.layoutIfNeeded()もほとんどの場合機能します。