setNeedsLayoutsetNeedsDisplay関連



Setneedslayout Setneedsdisplay Related



ランタイムビューの相互作用イベントシーケンスは次のとおりです。

  1. ユーザーのタッチスクリーン
  2. ハードウェアはタッチイベントをUIKitフレームワークに報告します
  3. UIKitフレームワークはタッチイベントをUIEventオブジェクトにパッケージ化し、適切なビューに配布します
  4. イベント処理コードは対応するイベントに応答し、コードは次のようになります。
  5. -変更frameboundsalpha属性
  6. -転送setNeedsLayoutレイアウトの更新に必要なビュー(またはそのサブビュー)をマークする方法
  7. -転送setNeedsDisplayまたはsetNeedsDisplayInRect: ビュー(またはそのサブビュー)をマークする方法を再描画する必要があります
  8. -通知コントローラーのデータが変更されました
  9. ビューのジオメトリが変更されると、UIKitはそのサブビューを更新します。
  10. ビューのいずれかの部分を再描画する必要があるとマークされている場合、UIKitはビューにそれ自体を再描画するように要求します
  11. 更新されたビューは、アプリケーションの残りのビジュアルコンテンツと組み合わされ、表示のためにグラフィックハードウェアに送信されます。
  12. グラフィックハードウェアは、解釈されたコンテンツを画面に変換します

いつトリガーされますかlayoutSubviews

  1. 初期化の初期化はlayoutSubviewsをトリガーしません
  2. addSubviewはlayoutSubviewsをトリガーします
  3. 設定の前後でフレームの値が変更された場合、ビューのフレームを設定すると、layoutSubviewsがトリガーされます。
  4. UIScrollViewをスクロールすると、layoutSubviewsがトリガーされます
  5. 画面を回転すると、親UIViewでlayoutSubviewsイベントがトリガーされます
  6. UIViewのサイズを変更すると、親UIViewのlayoutSubviewsイベントもトリガーされます。

いつ触れるのかdrawRect

1. UIViewの初期化中にrectサイズが設定されていない場合、drawRectが自動的に呼び出されなくなります。 drawRect呼び出しは、Controller-> loadView、Controller-> viewDidLoadメソッドの後に呼び出されます。したがって、心配しないでください。viewDidLoadでは、これらのビューのdrawRectが描画を開始します。これにより、ViewDidLoadのいくつかの値をビューに設定できます(これらのビューの描画にいくつかの変数値を使用する必要がある場合)。

2、このメソッドはsizeToFitを呼び出した後に呼び出されるため、最初にsizeToFitを呼び出してサイズを計算できます。次に、システムは自動的にdrawRect:メソッドを呼び出します。



3.contentModeプロパティをUIViewContentModeRedrawに設定します。その後、drawRect:は、フレームが設定または変更されるたびに自動的に呼び出されます。

4、直接setNeedsDisplay、またはsetNeedsDisplayInRect:trigger drawRect:を呼び出しますが、rectを0にすることはできないという前提条件があります。1、2、3、4を超えることは推奨されません。



drawRectメソッドは、次の点を使用します。

1. UIView描画を使用する場合、対応するcontextRefを取得し、drawRect:メソッドで描画することしかできません。別のメソッドを使用すると、invalidateの参照が取得され、描画に使用できなくなります。 drawRect:メソッドは呼び出しを手動で表示できません。システムは、setNeedsDisplayまたはsetNeedsDisplayInRectを呼び出してメソッドを自動的に調整する必要があります。

2. CALayer描画を使用する場合は、drawLayer:inContext:メソッド(drawRectと同様)でのみ描画するか、デリゲートの対応するメソッドで描画することしかできません。 setNeedDisplayを呼び出すことにより、同じメソッドが間接的に呼び出されます。



3、リアルタイムで描画したい場合は、gestureRecognizerを使用できません。touchbeganおよびその他のメソッドを使用して、setNeedsDisplayを使用して画面をリアルタイムで更新することしかできません。

setNeedsLayoutアプリケーションシナリオ

画面の回転、対応するUIの変更

setNeedsDisplayInRect: 使用するシーン

2点の間に線を引く必要がある場合、2つありますdotView a lineViewを描く必要があります。私はここにいますdrawRect:メソッドに実装されていますlineView特定の描画メソッド(2つのポイントに従って描画します)。したがって、この線を2つのポイントに基づいて同期的に変更する場合は、次のことを行う必要がありますdotView場所が変更されたら、次を実行します。

lineView.setNeedsDisplay() // redraw lineView

layoutIfNeeded

layoutIfNeededを使用すると、描画サイクルループがノードに到達する直前に、レイアウトの更新でlayoutSubviewsメソッドを呼び出すことができます。つまり、オブジェクトのレイアウト設定が変更されているか、以前にsetNeedsLayoutメソッドフラグが呼び出されていれば、layoutIfNeededを呼び出すとすぐに再レイアウトされます。そうでない場合、layoutIfNeededはlayoutSubviewsの呼び出しをトリガーしません。

応用

UIView.animateWithDuration(0.8, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: UIViewAnimationOptions.AllowAnimatedContent, animations: { self.leftContrain.constant = 100 }, completion: nil)

このコードは、制約を変更することでアニメーションを実現しようとしますが、効果がないことがわかります。これは、self.leftContrain.constant = 100がsetNeedsLayoutタグを実行したばかりであり、再レイアウトする必要があるが、すぐには実行されないためです。したがって、このメソッドlayoutIfNeededをアニメーションで呼び出す必要があります。コードは、次のように記述する必要があります。

leftContrain.constant = 100 UIView.animateWithDuration(0.8, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: UIViewAnimationOptions.AllowAnimatedContent, animations: { self.view.layoutIfNeeded() //Implement the layout immediately }, completion: nil)

したがって、いくつの制約が記述されていても、アニメーションでself.view.layoutIfNeeded()を1回使用するだけで、すべてがアニメーション化されます。一部の変更をアニメーション化したくない場合は、アニメーションの前にself.view.layoutIfNeeded()を実行します。

描画サイクルを表示

Appleの公式ドキュメント 開発者は直接電話してはならないことが明確に述べられています

layoutSubviewsdrawRect:代わりに、システムのデフォルトのレイアウトと再描画では目的の効果が得られないと思われる場合は、これらのメソッドをサブクラスで書き直して、別々に渡します。setNeedsLayout setNeedsDisplayInRect: で電話をかけます。

もちろん、複数のUIViewを設定することもできますsetNeedsLayout次に、次のビュー描画サイクルが到着すると、複数のUIViewのビューが一緒にレイアウトを変更します。

したがって、このビュー描画サイクルとは正確には何ですか、公式の説明は次のとおりです。


システムは、現在の実行ループが終了するまで待機してから、描画操作を開始します。この遅延により、複数のビューの無効化、階層からのビューの追加または削除、ビューの非表示、ビューのサイズ変更、およびビューの再配置を一度に行うことができます。行ったすべての変更は、同時に反映されます。


明らかに、RunLoopを使用して、複数の変更を1つのサイクルに集約し、それをレンダリングする方が効率的です。

(ビュー描画サイクルについての私の個人的な理解は次のとおりです。UIKitは多くのイベントを処理する必要があり、これらのイベントは非常に複雑な一連のイベントに結合されます。このシーケンスのいくつかの特定のポイントは、UIViewに特別に提供されるUIKitです。ビューを変更します。上記のように、現在の実行ループが終了する前に、さまざまなビューの変更を行う機会があり、これらの変更は次の実行ループに反映されるため、**ビュー描画サイクルはUIKitを渡すと実行ループになります。 UIViewの再レイアウトと再描画の機会のループ。誤解がある場合は、遠慮なくコメントしてください。)

参照リンク https://www.jianshu.com/p/c18c9e5db4d4

https://www.jianshu.com/p/e1eca032be15