2017-09-15 13 views
1

シンプルなので、私は自分自身が正しい解決策で苦労していることがわかります。viewDidLoadでUIViewフレームを正しく更新するための強制自動レイアウト

私は、自動レイアウトを使用した場合viewDidLoadREALUIView(またはその他のサブビュー)のフレームを見つけるため正しいの方法であるかを理解しようとしています。

viewDidLoadの主な問題は、ビューが制約に適用されないことです。私はこのような状況のための「既知」の答えは

override func viewDidLoad() { 
     super.viewDidLoad() 
    view.layoutIfNeeded() 
    stepContainer.layoutIfNeeded() // We need this Subview real frame! 
    let realFrame = stepContainer.frame 
} 

であることを知っているしかし、私はそれがの間違ったフレーム(すなわちない表示されている最終フレーム)を得、それは常に働いていないことが判明し、時間から時間まで。

さらに調査したところ、このコードをワープするとDispatchQueue.main.async { }という結果が得られました。しかし、それを正しく処理する方法がわからない場合や、これを使用して何らかの問題を引き起こしている場合は、私はよく分かりません。最終的な「作業」コード:

override func viewDidLoad() { 
     super.viewDidLoad() 

     DispatchQueue.main.async { 
      self. stepContainer.layoutIfNeeded() 
      print(self. stepContainer.frame) // Real frame.. 
     } 

} 

注:私は唯一のviewDidLoadから本当の枠が何であるかを見つける必要がある、コメントを読んだ後viewDidAppear/layoutSubviewsなど

+3

viewDidLoadは、フレームの知識が必要なものをセットアップする場所ではありません。そのため、この問題が発生しています。 – trapper

+0

@trapper私はこれを知っています。特定のシナリオのために、私はこれを解決する必要があります(解決できます)。私はそれを正しい方法で解決したことを確認しています。 –

+0

ビューのライフサイクルの早い段階でフレームと何をしようとしていますか? –

答えて

2

DavidRönnqvistが

を指摘@として派遣非同期は、ここであなたの「正しい」値を与える理由は、それが次回の実行ループで実行するようにスケジュールを取得 ということです。 viewWillAppear およびviewDidLayoutSubviewsを実行した後。

override func viewDidLoad() { 
    super.viewDidLoad() 
    DispatchQueue.main.async { 
    print("DispatchQueue.main.async viewDidLoad") 
    } 
} 

override func viewWillAppear(_ animated: Bool) { 
    super.viewWillAppear(animated) 

    print("viewWillAppear") 
} 

override func viewDidAppear(_ animated: Bool) { 
    super.viewDidAppear(animated) 

    print("viewDidAppear") 
} 

override func viewDidLayoutSubviews() { 
    super.viewDidLayoutSubviews() 

    print("viewDidLayoutSubviews") 
} 

viewWillAppear

viewDidLayoutSubviews

viewDidAppear

DispatchQueue.main.asyncのviewDidLoad

コード内DispatchQueue.main.asyncからviewDidLoadまでのコードがviewDidAppearの後にも呼び出されます。したがって、DispatchQueue.main.asyncviewDidLoadに入力すると、正しいフレームが得られますが、可能な限り早くはありません。あなたは可能な限り早期に、右側のフレームを取得したい場合は

  • 回答は、viewDidLayoutSubviewsはそれを行うには、正しい場所です。

  • がある場合は、viewDidLoadの中にコードを入れてください。 DispatchQueue.main.asyncのように見えるのが最善の方法です。

1

を使用することをお勧めしないでください変数を追加し、親ビューコントローラで

  • var viewSize : CGSize?
  • 、多分あなたは、コンテナに別のものにあなたのビューコントローラを埋め込み、このような何かをしようとすることができますあなたが保存されたサイズをお送り prepareForSegueで、親ビューコントローラで viewSize = view.size
  • var parentViewSize : CGSize?親ビューコントローラで
  • viewDidLayoutSubViewsでサイズを取得し、それを保存:子ビューコントローラで3210
  • は、変数を追加します。子ビューコントローラで(destinationViewController as? MyViewController)?.parentViewSize = viewSize
  • viewDidLoadにあなたはそれを行うだろう

それで良い値でparentViewSize変数にアクセスすることは?

1

質問はthis problemと似ていますが、私の回答も同じです。

フレームは、ビューが最終的に表示されるときと同じように、viewDidLoadで同じであることは保証されません。 UIKitは、表示されるコンテキストに基づいて、表示する前にView Controllerのビューのフレームを調整します。ビューのライフサイクルをよりよく理解するために、このイメージを参照できます。 enter image description here

イメージは、コードが動作している理由を理解するのに役立ちます。 ViewWillAppearは、ビューがロードされると呼び出され、dispatch asyncを設定すると、viewWillAppearの実行後にスレッドに非同期で追加されます。したがって、viewWillAppearが呼び出されると、ビューごとにフレームが更新され、dispatch asyncで正しいフレームが取得されます。

参考文献:あなたは、自動レイアウトを使用したい場合は、viewDidLayoutSubviewsのいずれかのフレームを管理

  1. :だから Image source

    For more information about view life cycle you can visit this answer

    、最後には、次の2つのオプションのいずれかのために行くことができますまたはviewWillAppear。 (これらのviewDidLayoutSubviewのいずれかで、viewWillAppearは、ビューが優先されるべきではないビュー階層の最上位に来るたびに呼び出されるため、必要です)。

  2. 自動レイアウトをスキップする場合は、プログラムでビューを作成して管理することができます。

希望します。

+0

この質問はhttps://stackoverflow.com/questions/14060002/wrong-frame-size-in-viewdidloadを見てください。私は 'viewWillAppear'は(1)のための正しい選択ではないと思います。 – trungduc

+0

同意する、だからこそ私も言及した。私はそれをより正確に編集します。それを指摘してくれてありがとう。 –

+0

ここに誤解があるようですね。私は* ios6でautolayoutを使用しているとき、フレームはサブビューが配置されるまで設定されません。これらの条件でフレームデータを取得する適切な場所は、viewControllerメソッドの 'viewDidLayoutSubviews' *です。その答えは**アップデート(ios6)**です。 – trungduc

関連する問題