web-dev-qa-db-fra.com

Qu'est-ce que _UITemporaryLayoutWidth et pourquoi brise-t-il mes contraintes?

J'ai un storyboard avec Autolayout et Classes de taille. Disposition assez compliquée, et malheureusement je ne peux pas vraiment déterminer comment reproduire le problème dans un nouveau projet.
Mais la vue en question est épinglée aux bords gauche et droit de l'écran avec une contrainte qui a une priorité de 750 (c.-à-d. |-(0@750)-[myView]-(0@750)-|, en plus elle a un supérieur ou égal à la contrainte avec une priorité de 1000 (c.-à-d. |-(>=0)-[myView]-(>=0)-|). Ceci est fait pour limiter la largeur sur un iPad, donc il y a une contrainte de largeur de width <= 600 @1000 et une contrainte centre horizontal dans le conteneur également. De plus, la vue a une contrainte de rapport d'aspect de 3: 1. Comme je l'ai dit, plutôt compliqué.

Interface Builder ne présente aucun problème avec les contraintes. L'aperçu de la disposition Xcode est correct pour tous les appareils.

Lorsque j'exécute l'application, iOS me dit qu'elle a des contraintes conflictuelles.

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>

Ceci est répété plusieurs fois, avec exactement les mêmes contraintes (c'est-à-dire le même pointeur). C'est étrange aussi, on dirait que la contrainte n'est pas vraiment cassée. Lorsqu'elle est exécutée, l'application semble 100% correcte. Lorsque je regarde l'application dans le débogueur de vue Xcode, la contrainte avec l'adresse 0x7ffb19798000 est toujours là, donc il n'a jamais été cassé.

Où le _UITemporaryLayoutWidth la constance vient? Évidemment, je ne l'ai pas ajouté. Google ne crache rien d'utile sur _UITemporaryLayoutWidth. Quelqu'un a-t-il rencontré un problème comme celui-ci?

44
Matthias Bauch

Donc, je ne sais pas si cela vous aide à résoudre votre problème, car il semble que vous construisez votre mise en page dans IB, mais voici un problème que je viens de rencontrer qui peut aider les autres utilisateurs de Google à rechercher "_UITemporaryLayoutWidth".

Mon scénario était que j'ajoutais des contraintes de mise en page automatique lors de l'initialisation et que je déclenchais accidentellement un "layoutIfNeeded" avant d'ajouter la vue à la hiérarchie des vues (la modification d'un bouton Les insertions de bord déclenchent la mise en page). Il semble que le système ajoute ces contraintes temporaires et (je suppose?) Les supprime une fois la vue ajoutée à la hiérarchie. Les contraintes temporaires définissent 0 dimensions (dans mon cas), ce qui peut échouer si vous, par exemple, définissez des valeurs de constante de contrainte spécifiques dans votre mise en page (par exemple, vous voulez 16 pixels entre ces boutons mais il n'y a aucun espace dans cette dimension ...)

Mise à jour: Enquête un peu plus et a constaté que la contrainte temporaire semble correspondre au cadre que vous utilisez pour initialiser la vue parent. Dans mon cas, le cadre que j'ai utilisé était de taille 0x0, donc la contrainte de temp a été évaluée par rapport à la taille 0x0, échouant ainsi. Vérifié que si j'initie avec une trame 5x5, je vois la même erreur avec la contrainte _UITemporaryLayoutWidth (5). L'autre chose que j'ai remarquée est que la contrainte semble être ajoutée et supprimée lors de l'évaluation de la disposition - si je casse juste avant de déclencher la disposition et d'analyser les contraintes, je ne vois pas les contraintes temporaires. Je ne vois pas non plus les contraintes après l'erreur, donc je soupçonne qu'elles synthétisent les contraintes temporaires, les ajoutent, les résolvent puis les suppriment.

pdate 2: Ok, peut-être que c'est TMI mais cela pourrait être utile à quelqu'un. Ma pensée actuelle est que ces contraintes temporaires sont un aperçu de la façon dont le système gère la manipulation de trames mixtes et la mise en page automatique dans une hiérarchie de vues unique. Dans mon cas, ma vue n'avait pas de parent et n'avait aucune contrainte définissant sa taille, mais elle avait une trame nulle, ce qui signifiait que le système supposait que c'était la taille qu'il devait utiliser lors de la résolution de la mise en page. Je pense que le système synthétise ces contraintes temporaires pour les vues dont les cadres sont définis explicitement pour résoudre le reste du système lors de sa traversée de la hiérarchie.

Mise à jour 3: Donc, j'ai rencontré à nouveau ce problème et je voulais partager un peu plus d'informations. Mon scénario était que j'essayais de mesurer essentiellement des vues qui n'avaient pas de parent en utilisant la méthode systemLayoutSizeFittingSize :. Pour faire court, j'ai dû appeler layoutIfNeeded sur la vue avant de la mesurer - c'est là que je rencontre le conflit avec les contraintes temporaires car la vue n'a pas de superview. Les constantes de contrainte de temp (les dimensions) correspondent à n'importe quel cadre défini sur la vue sans superview - je pense que cela a du sens (cependant, définir un cadre sur une vue que vous allez utiliser avec AutoLayout semble étrange .. .) J'ai pu contourner le problème des contraintes temporaires en disant - si la vue n'a pas de superview, ajoutez-la à une superview temporaire; mesure; supprimez-le de la vue d'ensemble temporaire. J'espère que c'est utile.

62
tyler

Comme mentionné ci-dessus, les contraintes temporaires semblent être définies sur les vues qui n'ont pas de vue parent. J'ai constaté qu'assurer que translatesAutoresizingMaskIntoConstraints est false dans la vue de niveau supérieur a supprimé les contraintes temporaires. Comme:

topView.translatesAutoresizingMaskIntoConstraints = false
17
Nick Ager

Dans mon cas, le problème était le suivant:

J'ai créé un UIButton.
J'ai défini ses contraintes de largeur et de hauteur.
J'ai ajouté le bouton à sa vue d'ensemble.
J'ai défini ses contraintes de mise en page principale et supérieure pour la vue d'ensemble.

Cela a créé l'erreur "Unable to simultaneously satisfy constraints "et l'une des contraintes conflictuelles était _UITemporaryLayoutHeight.

Lorsque j'ai ajouté le bouton à sa vue d'ensemble avant définissant ses contraintes de largeur et de hauteur, l'erreur a disparu.

12
Reinhard Männer

J'ai rencontré ce problème lorsque j'ai ajouté mes contraintes avec les ancres de mise en page d'une vue. Lorsque j'ai changé les contraintes des ancres de disposition-marges en ancres supérieure, inférieure, avant et arrière de la vue, l'erreur a disparu.

Je créais ma superview avec .zero rect.

Mais comme je devais incorporer des marges de vue, j'ai dû faire un petit hack. J'ai changé la priorité de mes contraintes.

J'obtenais des erreurs temporaires de largeur et de hauteur temporaires. J'ai donc abaissé la priorité d'une contrainte le long de l'axe horizontal et d'une contrainte le long de l'axe vertical (contraintes supérieure et inférieure dans ce cas):

    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

La raison en est que depuis que j'initialise ma vue avec .zero rect iOS ajoute automatiquement les contraintes temporaires de largeur et de hauteur. À ce stade, si nous ajoutons d'autres contraintes de priorité élevée, la génération des journaux d'erreurs sera interrompue.

L'abaissement de la priorité corrige les contraintes de rupture et lorsque les contraintes temporaires sont supprimées, notre vue prendra sa bonne forme.

3
HAK

Dans ma situation, je n'ai obtenu que ce conflit UITemporaryLayoutWidth dans cette situation 1 je crée une vue avec [UIView new], et je ne l'ajoute à aucune superview 2 puis je crée une contrainte de largeur à cette vue qui vient d'être créée 3 invoke layoutIfNeeded to cette vue immédiatement, et le conflit se produit

donc la façon d'éliminer cette erreur est simple: ne l'appellez pas layoutIfNeeded avant d'être ajouté à une vue d'ensemble

2
ximmyxiao

Juste un ajout rapide aux commentaires ci-dessus, la solution simple qui a fonctionné pour moi a été de changer l'ordre dans lequel mes contraintes étaient créées. Je créais par programme des contraintes sur les vues et les super-aperçus - mais je faisais les vues avant les super-aperçus. Je l'ai donc inversé pour que les contraintes de superview soient les premières, puis les sous-vues ont leurs contraintes ajoutées, ce qui signifie qu'il n'y a plus d'appel pour _UITemporaryLayoutWidth, et donc les problèmes de contraintes ont disparu.

2
Luke Smith

J'ai passé quelques heures sur ce problème aujourd'hui. Je définissais le contentMode de mon imageView UIButton immédiatement après l'initialisation de l'élément, ce qui semblait forcer une mise en page avant d'avoir configuré les contraintes dans ma classe de niveau supérieur (ce qui comprenait la limitation de la hauteur/largeur).

1
henshiee

Mon problème UITemporaryLayoutWidth était que je créais des boutons par programme et la contrainte tempWidth serait d'environ 0,1 sur ma contrainte de largeur. (Bien que ce soit ennuyeux, cela ne s'est produit que lors de la création de boutons de l'une des multiples façons dont j'ai créé les boutons)

Le problème était que j'utilisais .adjustsFontSizeToFitWidth = true pour le titre du bouton.

J'ai commenté cette ligne et elle est partie.

1
aestusLabs

La racine du problème est le rapport d'aspect 3: 1. Si je le change en quelque chose d'autre, cela fonctionne, j'utilise maintenant 4:1.4, qui fonctionne. Je ne sais pas pourquoi, mais ça marche.

Je ne connais pas grand-chose aux aspects internes de la mise en page automatique, mais je pense que le problème est l'ordre dans lequel le moteur de mise en page veut répondre aux contraintes. Les classes de taille peuvent être la raison pour laquelle la contrainte de largeur temporaire est ajoutée.

Les contraintes insatisfaisantes ne semblent pas être un vrai problème car il semble qu'elles ne soient insatisfiables que temporairement. Ce ne sont que quelques lignes de journal qui apparaissent chaque fois que la vue est créée.

0
Matthias Bauch