AutolayoutとSize Classsのストーリーボードがあります。かなり複雑なレイアウトで、残念ながら新しいプロジェクトで問題を再現する方法を正確に特定することはできません。
しかし、問題のビューは、750の優先順位を持つ制約(つまり、|-(0@750)-[myView]-(0@750)-|
、さらにを持つ制約で画面の左右の端に固定されています)優先度が1000の制約(つまり|-(>=0)-[myView]-(>=0)-|
)よりも大きいか等しいこれは、iPadで幅を制限するために行われるため、width <= 600 @1000
の幅制約があります、およびコンテナの水平中心制約も同様です。その上に、ビューには3:1のアスペクト比制約があります。複雑。
Interface Builderは制約の問題を表示しません。 Xcodeレイアウトのプレビューは、すべてのデバイスで正しくレンダリングされます。
アプリを実行すると、iOSにより、制約が競合していることが通知されます。
Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
"<NSLayoutConstraint:0x7fd72853ff80 DMXKit.DipSwitchAssembly:0x7fd72990d0e0.width == 3*DMXKit.DipSwitchAssembly:0x7fd72990d0e0.height>",
"<NSLayoutConstraint:0x7fd728574e50 '_UITemporaryLayoutWidth' H:[DMXKit.DipSwitchAssembly:0x7fd72990d0e0(400)]>",
"<NSLayoutConstraint:0x7fd72856e9c0 V:[DMXKit.DipSwitchAssembly:0x7fd72990d0e0(133)]>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x7ffb19798000 DMXKit.DipSwitchAssembly:0x7ffb1979a000.width == 3*DMXKit.DipSwitchAssembly:0x7ffb1979a000.height>
これは、まったく同じ(つまり、同じポインタ)制約で数回繰り返されます。それも奇妙なことですが、制約は実際には壊れていません。実行すると、アプリは100%正しく見えます。 Xcodeビューデバッガーでアプリを見ると、アドレス0x7ffb19798000
の制約がまだ残っているため、壊れることはありませんでした。
_UITemporaryLayoutWidth
constaintはどこから来たのですか?明らかに私はそれを追加しませんでした。 Googleは、_UITemporaryLayoutWidth
に関する有用な情報を出力しません。誰かがこのような問題に遭遇しましたか?
そのため、IBでレイアウトを構築しているように思われるため、これが問題の解決に役立つかどうかはわかりませんが、ここで私が遭遇した問題は、「_ UITemporaryLayoutWidth」をグーグル検索する他の人を助ける可能性があります。
私のシナリオでは、初期化中に自動レイアウト制約を追加し、ビューをビュー階層に追加する前に誤って「layoutIfNeeded」をトリガーしていた(ボタンエッジインセットトリガーレイアウトを変更)。システムがこれらの一時的な制約を追加し、ビューが階層に追加された後に(私はそうでしょうか?)それらを削除するようです。一時的な制約は0次元を設定し(私の場合)、たとえば、レイアウトに特定の制約定数値を設定した場合に失敗する可能性があります(たとえば、これらのボタンの間に16ピクセルが必要であるが、その次元にはスペースがない場合...)
pdate:もう少し調査したところ、一時的な制約が親ビューの初期化に使用するフレームに対応しているようです。私の場合、使用したフレームはサイズ0x0だったので、temp制約は0x0サイズと比較して評価され、失敗しました。 5x5フレームで初期化すると、_UITemporaryLayoutWidth(5)制約で同じエラーが表示されることを確認しました。もう1つ気づいたのは、レイアウトの評価中に制約が追加および削除されているように見えることです。レイアウトをトリガーする直前に中断して制約を分析すると、一時的な制約が表示されません。エラー後に制約も表示されないので、一時制約を合成し、追加して、解決してから削除したのではないかと思います。
pdate 2:わかりました、これはTMIかもしれませんが、これは誰かに役立つかもしれません。私の現在の考えでは、これらの一時的な制約は、システムが単一のビュー階層内の混合フレーム操作と自動レイアウトをどのように処理するかをのぞき見です。私の場合、ビューには親がなく、サイズを定義する制約もありませんでしたが、フレームがゼロでした。つまり、レイアウトを解決するときに使用するサイズであるとシステムが想定しました。私の考えでは、システムは、フレームが明示的に設定されているビューに対してこれらの一時的な制約を合成して、システムが階層をトラバースするときに残りのシステムを解決します。
pdate 3:したがって、私は再びこの問題に遭遇し、もう少し情報を共有したいと思いました。私のシナリオは、systemLayoutSizeFittingSize:メソッドを使用して、親のないビューを本質的に測定しようとしたことです。簡単に言えば、測定する前にビューでlayoutIfNeededを呼び出す必要がありました。ビューにはスーパービューがないため、一時的な制約との競合が発生します。一時的な制約の定数(寸法)は、スーパービューなしでビューに設定されたフレームに対応します-これは理にかなっていると思います(ただし、オートレイアウトで使用するビューにフレームを設定するのは奇妙に思えますが。 。)一時的な制約の問題を回避することができました。ビューにスーパービューがない場合は、一時的なスーパービューに追加します。測定;一時的なスーパービューから削除します。これがお役に立てば幸いです。
上記のように、一時的な制約は親ビューを持たないビューに設定されているように見えます。トップレベルのビューでtranslatesAutoresizingMaskIntoConstraints
がfalse
であることを確認すると、一時的な制約が削除されました。なので:
topView.translatesAutoresizingMaskIntoConstraints = false
私の場合、問題は次のとおりです:
UIButton
を作成しました。
幅と高さの制約を設定しました。
ボタンをスーパービューに追加しました。
私は、その主要および上部レイアウト制約をスーパービューに設定しました。
これによりエラー「Unable to simultaneously satisfy constraints
"と競合する制約の1つは_UITemporaryLayoutHeight
。
ボタンをスーパービューに追加したときbefore幅と高さの制約を設定すると、エラーが発生しなくなりました。
ビューのレイアウトマージンアンカーを使用して制約を追加したときに、この問題に直面しました。制約をレイアウトマージンアンカーからビューの上部、下部、リーディング、トレーリングアンカーに変更すると、エラーが消えました。
私は.zero
rectでスーパービューを作成していました。
しかし、私はビューのマージンを組み込む必要があったので、少しハックをしなければなりませんでした。制約の優先順位を変更しました。
一時的な幅と一時的な高さのエラーが発生しました。そのため、横軸に沿った1つの制約と縦軸に沿った1つの制約(この場合、上と後の制約)の優先度を下げました。
let topConstraint = stackView.topAnchor.constraint(equalTo: margins.topAnchor)
topConstraint.priority = .init(rawValue: 999.0)
topConstraint.isActive = true
let trailingConstraint = stackView.trailingAnchor.constraint(equalTo: margins.trailingAnchor)
trailingConstraint.priority = .init(rawValue: 999.0)
trailingConstraint.isActive = true
これは、.zero rectを使用してビューを初期化しているため、iOSは一時的な幅と高さの制約を自動的に追加するためです。現時点で、優先度の高い他の制約を追加すると、エラーログの生成が中断されます。
優先度を下げると、制約の違反が修正され、一時的な制約が削除されると、ビューが正しい形状になります。
私の状況では、この状況でこのUITemporaryLayoutWidth競合のみが発生しました1 [UIView new]でビューを作成し、それをスーパービューに追加しませんでした2次に、このビューに幅制約を作成します3作成されるlayoutIfNeededを呼び出しますこのビューはすぐに、そして紛争が起こります
したがって、このエラーを解消する方法は簡単です。いくつかのスーパービューに追加する前に、自分に対してlayoutIfNeededを呼び出さないでください
上記のコメントに簡単に追加すると、私にとって効果的な簡単な解決策は、制約が作成される順序を変更することでした。プログラムでビューとスーパービューの両方に制約を作成していましたが、スーパービューの前にビューを実行していました。そこで、スーパービューの制約が最初に表示されるように入れ替え、サブビューに制約を追加しました。これにより、_UITemporaryLayoutWidthの呼び出しがなくなり、制約の問題が解消されました。
今日、この問題に数時間費やしました。要素を初期化した直後にUIButton imageViewのcontentModeを設定していました。これにより、最上位クラス(高さ/幅の制限を含む)に制約を設定する前にレイアウトを強制するように見えました。
UITemporaryLayoutWidthの問題は、プログラムでボタンを作成していて、tempWidth制約が幅の制約から約0.1オフになることでした。 (厄介なことに、これは、ボタンを作成した複数の方法の1つでボタンを作成したときにのみ発生しました)
問題は、ボタンのタイトルに.adjustsFontSizeToFitWidth = trueを使用していたことでした。
その行をコメントアウトして、消えました。
問題の原因は、3:1のアスペクト比です。それを別の何かに変更した場合、機能する4:1.4
を使用します。理由はわかりませんが、うまくいきます。
自動レイアウトの内部についてはよくわかりませんが、問題は、レイアウトエンジンが制約をどのように満たすかという順序にあると思います。サイズクラスが、一時的な幅の制約が追加された理由である可能性があります。
満たされていない制約は、一時的にしか満たされないように見えるため、実際の問題ではないようです。これは、ビューが作成されるたびに表示される数行のログです。