2015-04-16 4 views
13

Ich bin mir bewusst, dass die Formeln frame.size.width/2 eine Kreisgrenze erzeugen sollte, aber in XCode erlebe ich derzeit einige Diskrepanzen.iOS: frame.size.width/2 erzeugt keinen Kreis auf jedem Gerät

Ich habe zwei Testgeräte (iPhone6 ​​und 5th Gen iPod touch) Ich habe auch den Simulator laufen. Sowohl meine Geräte korrekt angezeigt, aber der Simulator zieht meinen Kreis als Rechteck mit abgerundeten Ecken:

enter image description here

Der Code Ich verwende dieses Ziel zu erreichen (wenn auch sehr einfach) ist:

imgAvatar.layer.masksToBounds = true 
imgAvatar.clipsToBounds = true 
imgAvatar.layer.cornerRadius = imgAvatar.frame.size.width/2 
imgAvatar.layer.borderWidth = 5 
imgAvatar.layer.borderColor = UIColor.whiteColor().CGColor 

Gibt es ein Warum passiert das? Es macht mich wahnsinnig!

UPDATE Verwirrung zu löschen, wird die UIImageView in meinem Drehbuch erklärt als 190x190 es auch ein 1:1 Seitenverhältnis Zwang auf sie angewendet hat, um sicherzustellen, dass es eine proportionale Breite und Höhe hält.

UPDATE 2 jeden Verdacht setzen meine Auto-Layout in Bezug auf Einschränkungen zu Bett, habe ich das Bild unten angebracht, die die Einschränkungen für imgAvatar gesetzt zeigt. Wie Sie sehen können, stimmt die Breite und Höhe überein und der AR ist so eingestellt, dass er das 1: 1 Verhältnis beibehält. Ich hoffe, dass aufräumt weitere Zweifel

enter image description here

ANTWORT Leonardo eine äußerst praktische und wiederverwendbare Lösung dieses Problem hingewiesen zu beheben, Swift-Erweiterungen verwenden, kann man sicherstellen, dass ein bestimmte UIImage immer Platz ist, also immer einen Kreis zu erzeugen, ich habe Leonardos Lösung unten geschrieben:

extension UIImage { 
    var circleMask: UIImage { 
     let square = size.width < size.height ? CGSize(width: size.width, height: size.width) : CGSize(width: size.height, height: size.height) 
     let imageView = UIImageView(frame: CGRect(origin: CGPoint(x: 0, y: 0), size: square)) 
     imageView.contentMode = UIViewContentMode.ScaleAspectFill 
     imageView.image = self 
     imageView.layer.cornerRadius = square.width/2 
     imageView.layer.borderColor = UIColor.whiteColor().CGColor 
     imageView.layer.borderWidth = 5 
     imageView.layer.masksToBounds = true 
     UIGraphicsBeginImageContext(imageView.bounds.size) 
     imageView.layer.renderInContext(UIGraphicsGetCurrentContext()) 
     let result = UIGraphicsGetImageFromCurrentImageContext() 
     UIGraphicsEndImageContext() 
     return result 
    } 
} 

imgAvatar.image = yourImage.circleMask 
+2

Können Sie versuchen, die 'imgFrame', sowie die resultierende' cornerRadius' Eigenschaft zu protokollieren? (Beachten Sie, dass 'NSStringFromCGRect()' hier hilfreich sein könnte.) –

+0

Wo ist dieser Code (in welcher Methode)? – rmaddy

+0

Es ist in einer Methode namens 'initFrames', die in' viewDidLoad' aufgerufen wird – Alex

Antwort

14

Sie eine Erweiterung schaffen, die Maske und Grenze direkt auf Ihr Bild anzuwenden, so dass es immer die Bildschirmgröße/Skala abgesehen funktioniert:

extension UIImage { 
    var circleMask: UIImage { 
     let square = CGSize(width: min(size.width, size.height), height: min(size.width, size.height)) 
     let imageView = UIImageView(frame: CGRect(origin: CGPoint(x: 0, y: 0), size: square)) 
     imageView.contentMode = UIViewContentMode.ScaleAspectFill 
     imageView.image = self 
     imageView.layer.cornerRadius = square.width/2 
     imageView.layer.borderColor = UIColor.whiteColor().CGColor 
     imageView.layer.borderWidth = 5 
     imageView.layer.masksToBounds = true 
     UIGraphicsBeginImageContext(imageView.bounds.size) 
     imageView.layer.renderInContext(UIGraphicsGetCurrentContext()) 
     let result = UIGraphicsGetImageFromCurrentImageContext() 
     UIGraphicsEndImageContext() 
     return result 
    } 
} 

imgAvatar.image = yourImage.circleMask 
+1

Wow, ich liebe diese Lösung, meine erste Exposition zu Erweiterungen und das ist perfekt. Vielen Dank Leonardo! – Alex

+0

Sie sind willkommen –

+1

Ja das ist, was ich mit Unterklassen gemeint habe :). Wie auch immer, gute Antwort! –

2

Wenn Sie testen in iOS8.3, Sie layoutIfNeed auf Ihrem UI-Objekt aufrufen sollte vor ihrem Rahmen erhalten. Bitte lesen Sie iOS8.3 Release notes

Zum Beispiel:

UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem]; 
// code that sets up the button, but doesn’t yet add it to a window 
CGRect titleFrame = button.titleLabel.frame; 
// code that relies on the correct value for titleFrame 

Sie müssen jetzt:

UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem]; 
// code that sets up the button, but doesn’t yet add it to a window 
[button layoutIfNeeded]; // This is also safe pre-iOS 8.3 
CGRect titleFrame = button.titleLabel.frame; 
// code that relies on the correct value for titleFrame 

Es wird gesagt, dass für UIButton und Unterklassen, aber sie es auch mit Ihrem UI-Objekt ausprobieren können.

Bei der Verknüpfung gegen IOS 8.3, jeden Code, der auf dem Layout Informationen (wie etwa den Rahmen) einen UIButton subview setzt, wenn die Taste nicht in der Fensterhierarchie wird layoutIfNeeded zur Taste senden muß, bevor Abrufen von Layout-Informationen (wie button.titleLabel.frame), um sicherzustellen, dass die Layout-Werte bis zu Datum sind.

Auch als die der imgAvatar corner bis 1/2 imgFrame Größe eingestellt wurde, erhalten Sie einen Kreis nur, wenn dieser Wert erhalten = corner 1/2 imgAvatar der Breite (und Höhe).

Also, nach dem Aufruf:

imgAvatar.layer.cornerRadius = imgFrame.frame.size.width/2 

überprüfen:

  • Rahmengröße von imgAvatar und seine corner
  • sicher sein, dass Bild, das Sie
+0

Selbst das Aufrufen von 'layoutIfNeeded()' behebt dieses Problem nicht ... sehr seltsam - danke für den Vorschlag! :) – Alex

+0

Es ist ein UIImageView – Alex

+0

Was ist der Wert des Frames imgFrame? Es scheint, dass Ihr imgAvatar größer ist als imgView, das heißt, wenn Sie 1/2 Größe Ihres imgView verwenden, erzeugt der imgAvatar mit diesem Wert des Eckenradius keinen Kreis. –

0

Die Formel quadriert verwendet wird nur für quadratisches Bild arbeiten. Verwenden Sie das automatische Layout? Vielleicht könnte es für das Gerät, das Sie verwendet haben, gestreckt werden. Wenn dies der Fall ist, ist die Höhe höher als die Breite oder umgekehrt. Das heißt, das Bild wird eine Art Rechteck sein, und es wird keinen perfekten Kreis ergeben.

+0

Ich verwende die Formel auf die UIImageView und nicht die UIImage, die UIImageView ist ein 190 x 190 Quadrat, ich wendete 1: 1 Seitenverhältnis Einschränkungen und Breite/Höhe = 190. – Alex

+0

das ist sehr seltsam dann ... – Salihcyilmaz

8

Nun, sollte Automatische Anordnung das Problem sein. Wie zu sehen ist, ist die Höhe der imgAvatar auf rechts größer als die Höhe der imgAvatar auf links.

Die Größe imgAvatar rechts ist 190 x 190 und das auf der linken Seite ist 200 x 200, sondern auf der der Eckenradius nach links, die Sie setzen ist 190/2 dh 95px während Es sollte 100px sein.

gesetzt freundlichen Höhe & Breite Constraint in Ihrer NIB-Datei für imgAvatar, wenn Sie nicht möchten, den imgAvatar um 1, um die Größe: 1.

  1. Wählen Sie imgAvatar in Ihrer Schreibfeder aus.
  2. Editor> Pin> Höhe
  3. Wählen Sie imgAvatar in Ihrer Feder aus.
  4. Editor> Pin> Breite

ODER

Versuchen Sie, Ihren Code zu viewDidLayoutSubviews

ODER

Subclass Ihre UIImageView und setzen Sie den Eckenradius in seiner awakeFromNib Methode bewegt

Bitte lassen Sie uns wissen, ob es funktioniert hat. Vielen Dank!

+0

Siehe mein Update bezüglich Constraints – Alex

+0

Ja hatten Sie bereits über Ihr Verhältnis 1: 1 erwähnt. Behalte es also fest und verändere die Größe nicht, oder bewege deinen Code zu viewDidLayoutSubviews. Was passiert ist, wenn Sie den Eckenradius auf 95px einstellen, aber die Größe des Bildes automatisch im Verhältnis 1: 1 ändert und Sie es einstellen, bevor die Größe der Ansicht geändert wurde. –

+0

Ich sehe, das macht total Sinn - diese Lösung funktionierte auch für mich, wenn Code in 'viewDidLayoutSubviews' verschoben wurde. - Upvoted, aber akzeptiere Leonardos Antwort als schön für eine ausfallsichere Lösung – Alex

2

Das Problem ist, dass, wenn der Kreis angewandt wird, werden die Grenzen der Ansicht noch den Standard betrachtet (320x480) und so, wenn Sie Einschränkungen auf den Bildschirm im Zusammenhang gesetzt haben, wird das Bild größer sein auf iPhone 6/6+ zum Beispiel.

Es gibt verschiedene Lösung, aber wenn man ein schnelles wollen, nur den Code setzen:

imgAvatar.layer.cornerRadius = imgFrame.frame.size.width/2 

in - viewDidLayoutSubviews in Ihrem View-Controller oder in - layoutSubviews Ihrer Ansicht nach vor zu überprüfen, ob die corner anders von der Breite/2 des Bildrahmens. So etwas wie das:

if (imgAvatar.layer.cornerRadius != imgFrame.frame.size.width/2) { 
    imgAvatar.layer.cornerRadius = imgFrame.frame.size.width/2 
} 
Verwandte Themen