2016-06-03 10 views
1

Fire Xcode und für Klarheit Build nur zu sagen, 9.3, Universal-App. Also, vergleichen Sie 9.3 iPads mit 9.3 iPhones. Erstellen Sie Simulator und Geräte - Ausstellung Exponate auf beiden.Erschreckend wirkt sich die layoutIfNeeded-Sequenz auf iPad und iPhone anders aus; wie repariert man?

Die App dreht sich in alle vier Richtungen.

Haben Sie eine typische Situation, wo man so etwas tun ...

@IBOutlet weak var doorHeightPerScreen: NSLayoutConstraint! 

var heightFraction:CGFloat = 0.6 
    { 
    didSet 
     { 
     if (heightFraction > maxHeight) { heightFraction = maxHeight } 
     if (heightFraction < minHeight) { heightFraction = minHeight } 

     let h = view.bounds.size.height 
     spaceshipHeightPerScreen.constant = h * heightFraction 

     self.view.layoutIfNeeded() // holy! read on.... 
     } 
    } 

Beachten Sie die layoutIfNeeded() nach der Änderung der Beschränkung.

das typische Beispiel fort, haben Sie so etwas wie

override func viewDidLayoutSubviews() 
    { 
    super.viewDidLayoutSubviews() 
    heightFraction = (heightFraction) 
    // use "autolayout power" for perfection every pass. 

    // now that basic height/position is set, 
    save/load reactive positions... 
    position detail stuff... 
    } 

Check it out ... Ich war das den ganzen Tag zu tun und passiert nur iPhones zu verwenden.

Interessanterweise brauchen Sie nicht den Aufruf layoutIfNeeded.

@IBOutlet weak var doorHeightPerScreen: NSLayoutConstraint! 
var heightFraction:CGFloat = 0.6 
    { 
    didSet 
     { 
     if (heightFraction > maxHeight) { heightFraction = maxHeight } 
     if (heightFraction < minHeight) { heightFraction = minHeight } 
     let h = view.bounds.size.height 
     spaceshipHeightPerScreen.constant = h * heightFraction 
     } 
    } 

Funktioniert gut.

Aber am Ende des Tages legte ich es auf ein paar iPads und .... alles kaputt!

Immer wenn Sie Landschaft/Porträt drehen, Probleme.

Nach einem Kopf kratzen, erkannte ich, dass Sie unglaublich brauchen die layoutIfNeeded Anruf, auf iPad. Das ist auf dem IDENTISCHEN OS.

Tatsächlich zeigt das Verhalten unabhängig von der Betriebssystemversion. Und es zeigt für ALLE iPhones/ALLE iPads. WTF!

@IBOutlet weak var doorHeightPerScreen: NSLayoutConstraint! 
var heightFraction:CGFloat = 0.6 
    { 
    didSet 
     { 
     if (heightFraction > maxHeight) { heightFraction = maxHeight } 
     if (heightFraction < minHeight) { heightFraction = minHeight } 
     let h = view.bounds.size.height 
     spaceshipHeightPerScreen.constant = h * heightFraction 
     self.view.layoutIfNeeded() //MUST HAVE, IN IPAD CASE!!!!!! 
     } 
    } 

Für mich ist es unglaublich beunruhigend, dass sie anders funktionieren würde.

Was ich frage mich ist, gibt es vielleicht eine Einstellung irgendwo, damit sie gleich funktionieren? Könnte es irgendwie meine Schuld sein?

Gibt es noch andere bekannte Unterschiede zwischen den beiden - oder ist es tatsächlich "bekannt", dass es ein paar Bugs wie diesen gibt?

Ich kann nicht denken, etwas Ungewöhnliches oder Ungewöhnliches habe ich überall, außer die ganze App hat override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask { return .All } in der ersten Ansicht als normal ist, wenn Sie das Gerät auf den Kopf stellen wollen; Ich bezweifle es verwandt. Ansonsten ist es eine sehr "saubere" App.

Es gab mir ein Glitch-in-the-Matrix-Gefühl - es war erschreckend.

Was könnte das verursachen?

Pro RobM Frage sind die SimulatedMetrics Einstellungen (Registerkarte Attribute) auf dem ersten ViewController ...

enter image description here


Allgemeine Systematik der App: die erste Szene "General" ist Vollbild, die Größe des Gerätes. Es gibt einen Container für "Live", der die gleiche Größe hat (mit "Trailing" usw./Constraints als Null für alle). In Live gibt es eine Containeransicht "Quad", die in der Tat auch die Größe "Live" hat, also auch Vollbild. Quad: UIViewController zeigt das Problem, das ich beschreibe. Quad enthält verschiedene Objekte (Bilder, benutzerdefinierte Steuerelemente usw.), die auf der Ansicht herumliegen. Wenn die App startet, ist alles in Ordnung.

Bei Drehung des Gerätes (oder ähnlich): kurz nach der Änderung der Einschränkung (ich weiß nicht, ob das relevant ist): der layoutIfNeeded Anruf IST für iPads benötigt (alle iPads), aber ist NICHT benötigt für iPhones (alle iPhones). Das Verhalten ist im Simulator und auf Geräten identisch.


Ein weiteres Beispiel .....

ich ein weiteres erstaunliches Beispiel dafür gefunden.

In einer UICollectionView benutzerdefinierte Zellen (nur einfache statisch große Zellen). Wenn Sie eine Einschränkung ändern (stellen Sie sich vor, die Größe eines Symbols oder eines Produkts zu ändern, das in der Zelle aufgenommen wurde).

AUF IPAD Sie DO haben in layoutIfNeeded neu einzustellen, um sicherzustellen, oder es nicht auf dem ersten Auftreten der Zelle arbeiten.

Während ON IPHONE verhält es sich auf jeden Fall anders: es wird „das für Sie tun“, vor dem ersten Auftreten der Zelle, wenn Sie es weglassen passieren.

Völlig freaky !!

Ich habe das auf jedem iPad und jedem iPhone getestet. (Auch das ungewöhnliche Verhalten zeigt sich genau auf Geräten oder Simulatoren: Simulator macht keinen Unterschied.)

+0

Verwenden Sie ein Storyboard? Welche Größe haben die Ansichten im Storyboard? –

+0

Ich meine, welche Größe haben deine Szenen im Storyboard? –

+0

Klicken Sie auf den ersten View-Controller in Ihrem Storyboard. Öffnen Sie den Attribute-Inspektor. Was ist die "Größe" unter simulierten Metriken? –

Antwort

1

Ich bin nicht in der Lage zu reproduzieren, was Sie sehen; Es wäre schön, ein vollständiges Beispiel zu sehen. In meinem Modell konfigurierte ich einen View-Controller mit einer View, die eine einzelne Subview mit einer Einschränkung zur Kontrolle der Subview-Höhe hatte. Ich habe die Unteransicht Höhenbeschränkung in viewDidLayout basierend auf der Größe der Ansicht geändert. Das Verhalten war für iPhone und iPad identisch und funktionierte ohne Aufruf von layoutIfNeeded in jeder Ansicht.

Das sagte ich denken Sie ändern Subview-Einschränkungen, sobald die Ansicht ihr Layout abgeschlossen hat - ja? Ich denke, der bessere Weg dazu wäre, Ihre Subviews vorher über viewWillTransitionToSize:withTransitionCoordinator: zu planen.

Auf diese Weise kann das automatische Layout für die Ansichtshierarchie in einem einzigen Durchgang abgeschlossen werden. Diese Methode wird nur aufgerufen, wenn die Ansicht die Größe ändert. Daher wird sie beim ersten Laden der Ansicht nicht aufgerufen. Sie müssen Ihre anfänglichen Einschränkungen woanders einrichten - da sie abhängig von der Größe der Ansicht sind, können Sie vielleicht viewWillAppear verwenden.

Alternativ (und möglicherweise auch korrekter) Unterklasse der View-Controller-Ansicht und überschreiben updateConstraints. Dies ist der am besten geeignete Ort zum Ändern Ihrer Constraint-Konstanten.

Schließlich sollten Sie in Ihrem Property-Setter nie view.layoutIfNeeded() aufrufen. Wenn überhaupt, können Sie view.setNeedsLayout() festlegen, sodass das Layout in der nächsten Runloop-Iteration stattfindet, und alle Änderungen, die möglicherweise dargestellt werden müssen, werden angezeigt.

+0

Hallo Tom! ja, ich werde versuchen, ein komplettes Beispiel so schnell wie möglich zu machen ... – Fattie

+0

Ahh! Beachten Sie, dass 'heightFraction' dynamisch ist und ständig geändert wird. (Denken Sie daran, dass Sie etwas mit einem Schieberegler ändern können, sagen Sie. Es zeigt ein Raumschiff oder was auch immer auf dem Bildschirm, und der Benutzer kann den Höhenanteil ändern.) Natürlich ist es völlig normal (aus welchen Gründen auch immer), Einschränkungen zu ändern (ich meine zur Laufzeit), Dinge auf dem Bildschirm zu bewegen ... (Entschuldigung, ich dachte, dass das aus dem Codebeispiel offensichtlich ist, es ist eine Eigenschaft und Variable Namen.) Daher, wie Sie sagen "Ich habe die Unteransicht Höhe Einschränkung in ... geändert" fügen Sie einfach einen Schieberegler, um die Eigenschaft während der Verwendung zu ändern. – Fattie

+0

Re Ihre Vorschläge in den Absätzen 2, 3, 4; Ich werde mich darum kümmern, danke. ** ABER ** beachten Sie, dass das Problem in der Hand ist - auch wenn ich etwas nicht-idiomatisch, oder sogar "falsch" - unglaublich es funktioniert auf den beiden Gerätetypen anders !! : O – Fattie

1

Die standardmäßig simulierte Metrikengröße wird "abgeleitet", die (wenn die Szene nicht das Ziel eines Segments oder einer Beziehung ist) gibt Sie haben eine 600x600 Ansicht, die nicht der Bildschirmgröße eines iOS-Geräts entspricht. Sie haben die simulierte Metrikgröße irgendwann auf "iPhone 5.5" geändert, wahrscheinlich um die Größe Ihres Haupttestgeräts zu erreichen.

Wenn eine Ansicht aus einem Storyboard (oder XIB) geladen wird, wird sie in der Größe geladen, die sie im Storyboard hatte. Es kann dann von seinem Container in der Größe geändert werden (entweder UIWindow, wenn es sich um die Stammansicht der App handelt, oder um dessen Superview, wenn es sich um die Stammansicht eines enthaltenen Ansichtscontrollers handelt).

In Ihrem Fall klingt es so, als ob der Bildschirm Ihres Haupttestgeräts die gleiche Größe wie die Stammansicht in Ihrem Storyboard hat, sodass das Testgerät nicht so viel Layout ausführen muss, wie Sie erwarten.

Wenn Sie ein Testgerät verwenden, dessen Bildschirmgröße sich von der Größe Ihrer Stammansicht im Storyboard unterscheidet, muss das Testgerät mehr Layout erstellen.

Ich habe nicht versucht, Ihr Problem zu reproduzieren, also behaupte ich nicht, dass dies eine vollständige Erklärung dessen ist, was Sie sehen. Möglicherweise ist ein iOS-Bug beteiligt. Dies sollte jedoch erklären, warum sich Ihre App auf verschiedenen Geräten unterschiedlich verhält. Ich glaube, das ist auch der Grund, warum Apple die standardmäßige abgeleitete Größe von 600x600 auswählte: Da kein Gerätebildschirm diese Größe hat, müssen alle Geräte dieselbe Menge an Layout vornehmen.

+0

HI Rob, erstaunlich! Danke, ich werde nachforschen. Im Moment scheint die Aufteilung zwischen allen iPhones (beliebige Form) und allen iPads zu liegen. Ich werde das überprüfen! – Fattie

+0

"Wenn eine Ansicht von einem Storyboard (oder Xib) geladen wird, wird sie in der Größe geladen, die sie im Storyboard hatte." Das ist erstaunlich, das wusste ich nicht: Ich nahm an, dass die Einstellung dort völlig irrelevant war und nur mit der Darstellung auf dem Storyboard zusammenhing. – Fattie

+0

Hmm, ich habe es überprüft und es scheint nicht zu beeinflussen: so, (1) kommentieren Sie die Linie - Problem zeigt auf iPads (perfekt auf allen Handys). Ändern Sie Simulierte Metriken/Anfangsszene zu "iPad". Das Problem besteht weiterhin auf iPads (immer noch perfekt auf allen Handys). (2) die Codezeile an das Programm zurücksenden: perfekt auf allen iPads/iPhones (2B) und simulierte Metriken auf "iPad" ändern, immer noch perfekt auf allen iPads/iPhones. Umgekehrt, wenn Sie es als "sollte auch auf dem iPhone ausfallen, wenn Zeile kommentiert" - das gleiche Verhalten passiert ("immer noch auf dem iPhone") unabhängig von simulierten Metrik ... – Fattie