So wird UIView als Kreis mit Eckenradius mit Xcode 8 angezeigt

9

Ich habe ein Problem mit der Einstellung des Eckenradius in der Ansicht, da seit der Xcode-Aktualisierung auf 8 die Rahmen der Ansichten in den meisten Fällen auf 1000x1000 statt der entsprechenden Größe eingestellt sind.

Es gibt eine ähnliche Frage hier , aber ich würde gerne etwas mehr hinzufügen, in der Hoffnung, dass jemand die Antwort gefunden hat oder ein Workaround.

In einer der Instanzen habe ich eine Tabellenansichtszelle, in der eine Bildansicht im Storyboard erstellt wurde. Seine Breite und Höhe werden als Konstante mit Einschränkung (bis 95) festgelegt. Der Eckenradius wird in layoutSubviews festgelegt, das bisher funktioniert hat:

%Vor%

Also habe ich ein wenig mit Trial and Error herumgespielt und die Situation scheint etwas besser zu laufen, wenn ich versuche, das Layout nach dem Setzen des Bildes auszulösen (ein Bild wird vom Remote-Server abgerufen), indem ich Folgendes anrufe:

%Vor%

Das funktioniert in den meisten Fällen immer noch nicht. Jetzt der lustige Teil:

Ich habe einen Fall dieses View-Controllers in der Tab-Leiste, wo ich, wenn ich den Tab mit dem Target-View-Controller drücke, sofort Subviews aufrufen werde (aus UIApplicationMain ), wo die Größe der Image-View 1000x1000 ist Aber sobald das Bild gesetzt ist und ich die Layout-Methoden aufgerufen habe, werden die Layout-Subviews mit der korrekten Bildansichtsgröße von 95x95 erneut aufgerufen, um ein korrektes Ergebnis zu erhalten.

Die zweite Situation ist, dass der View-Controller des gleichen Typs gedrückt wird, bei dem jetzt das Layout nicht zuerst aufgerufen wird, der einzige Aufruf erfolgt, nachdem das Bild gesetzt und das Layout erzwungen wurde. Das Ergebnis ist wieder eine Bildansicht der Größe 1000x1000, wobei der Eckenradius auf 500 eingestellt wird und das Bild nicht sichtbar ist.

Gibt es also eine nette Lösung, um diese seltsamen Rahmenwerte zu korrigieren? Ich habe das gleiche Problem auf mehreren View-Controllern, Tabellenansicht Zellen. Es hat alles bis zum Update funktioniert.

Hat jemand irgendwelche Ideen, was ist die Ursache für dieses Problem überhaupt? Ist es aus dem Storyboard oder eine Art von Einstellungen Migration oder ist dies ein Layout-Fehler mit dieser Version der Software eingeführt?

Ich habe jetzt auch die wake from nib hinzugefügt:

%Vor%

Was nun dazu führt, dass das Layout in meinem Fall mindestens zweimal und das zweite Mal korrekt ist. Aber das ist bei weitem nicht die Antwort, das ist schrecklich und ich würde es gerne sehen, da ich es für alle Zellen für die einzelnen Bildansichten verwenden müsste, Buttons.

    
Matic Oblak 26.09.2016, 12:31
quelle

7 Antworten

7

Können Sie Ihre Methode einfach auf

aktualisieren? %Vor%

und geben Sie einen Versuch.

In einem meiner Fälle habe ich es versäumt, clipsToBounds = TRUE; zu setzen und es hat es nicht zum Kreisen gebracht.

    
Pushkraj 26.09.2016 12:50
quelle
1

Ich nehme an, dass die layoutSubviews Überschreibung, die in der Frage angezeigt wird, eine benutzerdefinierte Unterklasse von UITableViewCell ist.

Das Problem hier ist wahrscheinlich, dass myImageView keine direkte Unteransicht der Zelle ist.

Es ist wichtig zu verstehen, dass der Aufruf der Zelle an [super layoutSubviews] nur die Frames der direkten Subviews der Zelle festlegt. Es geht nicht den ganzen Weg in der Ansichtshierarchie vor der Rückkehr. Die Zelle hat normalerweise nur eine direkte Unteransicht: ihre contentView . Der Aufruf von [super layoutSubviews] setzt also nur den Rahmen der Inhaltsansicht und kehrt dann zurück. Der Versuch, self.myImageView.layer.cornerRadius zu setzen, geschieht zu früh, weil self.myImageView.frame noch nicht aktualisiert wurde.

Später, nachdem die layoutSubviews -Methode der Zelle zurückgegeben wurde, sendet UIKit die Nachricht layoutSubviews an die Inhaltsansicht. Zu diesem Zeitpunkt setzt die Inhaltsansicht ihre eigenen Frames der direkten Unteransicht. Das ist, wenn der Rahmen von myImageView gesetzt wird.

Die einfachste Lösung besteht darin, eine UIImageView -Unterklasse zu erstellen und ihre layoutSubviews zu überschreiben, um ihren eigenen Eckenradius festzulegen.

%Vor%

AKTUALISIEREN

Matic Oblak fragt (in einem Kommentar): "Ist das, was du hier geschrieben hast, testbar?"?

Ja, es ist testbar. Hier eine Möglichkeit, es zu testen: Erstellen Sie eine Ansichtshierarchie mit einer Stammansicht, einer Containeransicht in der Stammansicht und einer Blattansicht in der Containeransicht:

Überschreibe layoutSubviews in der Stammansicht und der Containeransicht, um die Rahmen der Ansichten zu drucken:

%Vor%

Sehen wir uns als gutes Beispiel auch an, ob die viewWillLayoutSubviews und viewDidLayoutSubviews des View-Controllers ausgeführt werden:

%Vor%

Schließlich führen Sie es auf einem Gerät oder einer Simulation mit einer anderen Größe als im Storyboard aus und schauen Sie sich die Debug-Konsole an:

%Vor%

Beachten Sie, dass das [super layoutSubviews] der Stammansicht den Rahmen der Containeransicht ändert, aber nicht den Rahmen der Blattansicht ändert. Die [super layoutSubviews] der Containeransicht ändert dann die Größe der Blattansicht.

Wenn layoutSubviews in einer Ansicht ausgeführt wurde, können Sie daher annehmen, dass die Frames der direkten Untersichten der Ansicht aktualisiert wurden, aber Sie müssen davon ausgehen, dass die Frames von tiefer verschachtelten Ansichten nicht wurde aktualisiert.

Beachten Sie auch, dass viewDidLayoutSubviews ausgeführt wird, nachdem die Ansicht des View-Controllers layoutSubviews ausgeführt hat, aber vor , dass die tiefer verschachtelten Nachkommen layoutSubviews ausgeführt haben. In viewDidLayoutSubviews müssen Sie also erneut davon ausgehen, dass die Frames der tiefer verschachtelten Ansichten nicht aktualisiert wurden.

Es gibt eine Möglichkeit, den Frame einer tief verschachtelten Subview sofort zu aktualisieren: sende layoutIfNeeded an seine Superview. Zum Beispiel kann ich -[RootView layoutSubviews] ändern, um layoutIfNeeded an _leafView.superview zu senden:

%Vor%

(Beachten Sie, dass in diesem Beispielprojekt _leafView.superview _containerView ist, aber im Allgemeinen nicht.) Hier ist das Ergebnis:

%Vor%

Nun habe ich UIKit gezwungen, den Rahmen von _leafView zu aktualisieren, bevor -[RootView layoutSubviews] zurückkehrt.

Was "Ich nehme an, viele Operationen wie das Setzen eines einfachen Textes auf dem Etikett wird setNeedsLayout aufrufen": Sie können die gleiche Technik verwenden, die ich gerade demonstriert habe, um die Antwort auf diese Frage herauszufinden.

    
rob mayoff 24.01.2018 07:38
quelle
0

Ich habe eine Demo-Anwendung erstellt, um zu sehen, welche Mindestanforderungen für dieses Problem erfüllt sind, und es ist ziemlich niedrig:

  • Erstellen Sie eine neue Single-View-Anwendung
  • Fügen Sie eine Tabellenansicht auf dem Hauptansicht-Controller hinzu
  • Fügen Sie der Tabellenansicht eine Zelle hinzu und überschreiben Sie deren Klasse als neue Tabellenansichtszellenunterklasse
  • Fügen Sie der Zelle eine Bildansicht mit festen Einschränkungen für Breite und Höhe hinzu (fügen Sie auch führende und obere Einschränkungen hinzu)
  • Setzen Sie in der Zelle layoutSubviews den Eckenradius der Bildansicht auf die Hälfte der Bildansichtsbreite (das Ergebnis wird immer 500 sein)

Die Bildansicht wird nicht angezeigt, da der Eckenradius 500 ist.

Also habe ich nach einer minimalen Korrektur gesucht und aus früheren Tests scheint es, dass das Layout den ersten Aufruf nicht enthält, also habe ich es hinzugefügt, indem ich die "wake from nib" überschrieben habe:

%Vor%

Also in dem Projekt, an dem ich gerade arbeite, habe ich eine neue Unterklasse einer Tabellenansichtszelle erstellt, und ich habe die "wake from nib" überschrieben. Dann habe ich alle anderen Zellen zu einer Unterklasse gemacht. Es ist keine Lösung, aber es ist ein Workaround, und da ich 57 Tabellenansicht Zelle Unterklassen habe, war diese Prozedur ziemlich schnell zu implementieren.

    
Matic Oblak 27.09.2016 07:40
quelle
0

Wenn Sie nur die @ pushkraj-Antwort für die runde Ansicht hinzufügen, sollten Ihre UIView-Breite und -Höhe gleich sein.

Dann können Sie tun.

%Vor%     
Mohammed Hussain 30.01.2018 09:45
quelle
-1

Versuchen Sie, die drawRect: -Methode in der UIImageView-Unterklasse zu überschreiben und dann den Eckenradius festzulegen.

%Vor%     
user16011990 30.01.2018 06:00
quelle
-1

Das kannst du so machen

%Vor%

Das wird für Sie funktionieren. Sehen Sie, warum Maskierungen für Grenzen erforderlich sind Link hier

    
Dhiru 31.01.2018 06:54
quelle
-2

swift 4

%Vor%     
Deepak Tagadiya 30.01.2018 13:09
quelle