Ich habe die Antwort unter Wie erstelle ich ein UILabel mit runden Ecken auf dem iPhone? und der Code von Wie wird eine abgerundete rechte Ansicht mit Transparenz auf dem iPhone erstellt? um diesen Code zu machen.
Dann wurde mir klar, dass ich die falsche Frage beantwortet hatte (gab ein abgerundetes UILabel anstelle von UIImage), also habe ich diesen Code verwendet, um ihn zu ändern:
http://discussions.apple.com/thread.jspa?threadID=1683876
Erstellen Sie ein iPhone-Projekt mit der Ansichtsvorlage. Fügen Sie im Ansichts-Controller Folgendes hinzu:
- (void)viewDidLoad
{
CGRect rect = CGRectMake(10, 10, 200, 100);
MyView *myView = [[MyView alloc] initWithFrame:rect];
[self.view addSubview:myView];
[super viewDidLoad];
}
MyView
ist nur eine UIImageView
Unterklasse:
@interface MyView : UIImageView
{
}
Ich hatte noch nie Grafikkontexte verwendet, aber ich habe es geschafft, diesen Code zusammen zu humpeln. Es fehlt der Code für zwei der Ecken. Wenn Sie den Code lesen, können Sie sehen, wie ich dies implementiert habe (indem Sie einige der CGContextAddArc
Aufrufe und einige der Radiuswerte im Code löschen. Der Code für alle Ecken ist vorhanden. Verwenden Sie ihn also als Ausgangspunkt und löschen Sie den Code Teile, die Ecken erstellen, die Sie nicht benötigen. Beachten Sie, dass Sie bei Bedarf auch Rechtecke mit 2 oder 3 abgerundeten Ecken erstellen können.
Der Code ist nicht perfekt, aber ich bin sicher, Sie können ihn ein wenig aufräumen.
static void addRoundedRectToPath(CGContextRef context, CGRect rect, float radius, int roundedCornerPosition)
{
// all corners rounded
// CGContextMoveToPoint(context, rect.origin.x, rect.origin.y + radius);
// CGContextAddLineToPoint(context, rect.origin.x, rect.origin.y + rect.size.height - radius);
// CGContextAddArc(context, rect.origin.x + radius, rect.origin.y + rect.size.height - radius,
// radius, M_PI / 4, M_PI / 2, 1);
// CGContextAddLineToPoint(context, rect.origin.x + rect.size.width - radius,
// rect.origin.y + rect.size.height);
// CGContextAddArc(context, rect.origin.x + rect.size.width - radius,
// rect.origin.y + rect.size.height - radius, radius, M_PI / 2, 0.0f, 1);
// CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, rect.origin.y + radius);
// CGContextAddArc(context, rect.origin.x + rect.size.width - radius, rect.origin.y + radius,
// radius, 0.0f, -M_PI / 2, 1);
// CGContextAddLineToPoint(context, rect.origin.x + radius, rect.origin.y);
// CGContextAddArc(context, rect.origin.x + radius, rect.origin.y + radius, radius,
// -M_PI / 2, M_PI, 1);
// top left
if (roundedCornerPosition == 1) {
CGContextMoveToPoint(context, rect.origin.x, rect.origin.y + radius);
CGContextAddLineToPoint(context, rect.origin.x, rect.origin.y + rect.size.height - radius);
CGContextAddArc(context, rect.origin.x + radius, rect.origin.y + rect.size.height - radius,
radius, M_PI / 4, M_PI / 2, 1);
CGContextAddLineToPoint(context, rect.origin.x + rect.size.width,
rect.origin.y + rect.size.height);
CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, rect.origin.y);
CGContextAddLineToPoint(context, rect.origin.x, rect.origin.y);
}
// bottom left
if (roundedCornerPosition == 2) {
CGContextMoveToPoint(context, rect.origin.x, rect.origin.y);
CGContextAddLineToPoint(context, rect.origin.x, rect.origin.y + rect.size.height);
CGContextAddLineToPoint(context, rect.origin.x + rect.size.width,
rect.origin.y + rect.size.height);
CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, rect.origin.y);
CGContextAddLineToPoint(context, rect.origin.x + radius, rect.origin.y);
CGContextAddArc(context, rect.origin.x + radius, rect.origin.y + radius, radius,
-M_PI / 2, M_PI, 1);
}
// add the other corners here
CGContextClosePath(context);
CGContextRestoreGState(context);
}
-(UIImage *)setImage
{
UIImage *img = [UIImage imageNamed:@"my_image.png"];
int w = img.size.width;
int h = img.size.height;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(NULL, w, h, 8, 4 * w, colorSpace, kCGImageAlphaPremultipliedFirst);
CGContextBeginPath(context);
CGRect rect = CGRectMake(0, 0, w, h);
addRoundedRectToPath(context, rect, 50, 1);
CGContextClosePath(context);
CGContextClip(context);
CGContextDrawImage(context, rect, img.CGImage);
CGImageRef imageMasked = CGBitmapContextCreateImage(context);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
[img release];
return [UIImage imageWithCGImage:imageMasked];
}
Alternativtext http://nevan.net/skitch/skitched-20100224-092237.png
Vergessen Sie nicht, dass Sie das QuartzCore-Framework benötigen, damit dies funktioniert.
Ab iOS 3.2 können Sie die Funktionalität von
UIBezierPath
s verwenden, um ein sofort einsatzbereites abgerundetes Rechteck zu erstellen (wobei nur die von Ihnen angegebenen Ecken abgerundet sind). Sie können dies dann als Pfad von aCAShapeLayer
und als Maske für die Ebene Ihrer Ansicht verwenden:Und das war's - kein Herumspielen des manuellen Definierens von Formen in Core Graphics, kein Erstellen von Maskierungsbildern in Photoshop. Die Ebene muss nicht einmal ungültig gemacht werden. Das Anwenden der abgerundeten Ecke oder das Ändern einer neuen Ecke ist so einfach wie das Definieren einer neuen Ecke
UIBezierPath
und deren VerwendungCGPath
als Pfad der Maskenebene. Dercorners
Parameter derbezierPathWithRoundedRect:byRoundingCorners:cornerRadii:
Methode ist eine Bitmaske, sodass mehrere Ecken durch ODER-Verknüpfung abgerundet werden können.BEARBEITEN: Hinzufügen eines Schattens
Wenn Sie dem einen Schatten hinzufügen möchten, ist etwas mehr Arbeit erforderlich.
Da "
imageView.layer.mask = maskLayer
" eine Maske anwendet, wird ein Schatten normalerweise nicht außerhalb der Maske angezeigt. Der Trick besteht darin, eine transparente Ansicht zu verwenden und dann zwei UnterebenenCALayer
zur Ebene der Ansicht hinzuzufügen :shadowLayer
undroundedLayer
. Beide müssen das nutzenUIBezierPath
. Das Bild wird als Inhalt von hinzugefügtroundedLayer
.quelle
Ich habe diesen Code an vielen Stellen in meinem Code verwendet und er funktioniert zu 100% korrekt. Sie können jeden Corder ändern, indem Sie eine Eigenschaft "byRoundingCorners: UIRectCornerBottomLeft" ändern.
quelle
UITableView
Unteransichten (z. B.UITableViewCell
s oderUITableViewHeaderFooterView
s) verwenden, führt dies zu einer schlechten Glätte beim Scrollen . Ein anderer Ansatz für diese Verwendung ist diese Lösung mit einer besseren Leistung (sie fügt allen Ecken einen CornerRadius hinzu). Um nur bestimmte abgerundete Ecken anzuzeigen (wie die oberen und unteren rechten Ecken), habe ich eine Unteransicht mit einem negativen Wert hinzugefügtframe.origin.x
und der Ebene denRadius zugewiesen. Wenn jemand eine bessere Lösung gefunden hat, bin ich interessiert.In iOS 11 können wir jetzt nur einige Ecken abrunden
quelle
CALayer Verlängerung mit Swift 3+ Syntax
Es kann verwendet werden wie:
quelle
Stuarts Beispiel zum Abrunden bestimmter Ecken funktioniert hervorragend. Wenn Sie mehrere Ecken wie oben links und rechts abrunden möchten, gehen Sie wie folgt vor
quelle
UITableView
Unteransichten (z. B.UITableViewCell
s oderUITableViewHeaderFooterView
s) verwenden, führt dies zu einer schlechten Glätte beim Scrollen . Ein anderer Ansatz für diese Verwendung ist diese Lösung mit einer besseren Leistung (sie fügt allen Ecken einen CornerRadius hinzu). Um nur bestimmte abgerundete Ecken anzuzeigen (wie die oberen und unteren rechten Ecken), habe ich eine Unteransicht mit einem negativen Wert hinzugefügtframe.origin.x
und der Ebene denRadius zugewiesen. Wenn jemand eine bessere Lösung gefunden hat, bin ich interessiert.Danke für das Teilen. Hier möchte ich die Lösung auf Swift 2.0 zur weiteren Bezugnahme auf dieses Problem teilen. (um das UIRectCorner-Protokoll anzupassen)
quelle
Es gibt eine einfachere und schnellere Antwort, die je nach Ihren Anforderungen funktioniert und auch mit Schatten funktioniert. Sie können maskToBounds auf der Superlayer auf true setzen und die untergeordneten Ebenen so versetzen, dass 2 ihrer Ecken außerhalb der Superlayer-Grenzen liegen, wodurch die abgerundeten Ecken auf 2 Seiten effektiv abgeschnitten werden.
Dies funktioniert natürlich nur, wenn Sie nur zwei abgerundete Ecken auf derselben Seite haben möchten und der Inhalt der Ebene gleich aussieht, wenn Sie einige Pixel von einer Seite abschneiden. funktioniert hervorragend, wenn Balkendiagramme nur auf der Oberseite gerundet sind.
quelle
Siehe diese verwandte Frage . Sie müssen Ihr eigenes Rechteck
CGPath
mit einigen abgerundeten Ecken zu einem zeichnen , dasCGPath
zu Ihrem hinzufügenCGContext
und dann mit verwendenCGContextClip
.Sie können auch das abgerundete Rechteck mit Alpha-Werten in ein Bild zeichnen und dann mit diesem Bild eine neue Ebene erstellen, die Sie als
mask
Eigenschaft Ihrer Ebene festlegen ( siehe Apple-Dokumentation ).quelle
Ein halbes Jahrzehnt zu spät, aber ich denke, die derzeitige Vorgehensweise ist nicht 100% richtig. Viele Leute hatten das Problem, dass die Verwendung der UIBezierPath + CAShapeLayer-Methode das automatische Layout beeinträchtigt, insbesondere wenn es im Storyboard festgelegt ist. Da keine Antworten darauf eingehen, habe ich beschlossen, meine eigenen hinzuzufügen.
Es gibt eine sehr einfache Möglichkeit, dies zu umgehen: Zeichnen Sie die abgerundeten Ecken in die
drawRect(rect: CGRect)
Funktion.Wenn ich beispielsweise obere abgerundete Ecken für eine UIView haben möchte, würde ich UIView unterordnen und diese Unterklasse gegebenenfalls verwenden.
Dies ist der beste Weg, um das Problem zu lösen, und es dauert überhaupt keine Zeit, sich daran zu gewöhnen.
quelle
drawRect(_:)
wenn Sie in Ihrer Ansicht benutzerdefinierte Zeichnungen erstellen (z. B. mit Core Graphics). Andernfalls kann selbst eine leere Implementierung die Leistung beeinträchtigen. Es ist auch nicht erforderlich, jedes Mal eine neue Maskenebene zu erstellen. Alles, was Sie tatsächlich tun müssen, ist, diepath
Eigenschaft der Maskenebene zu aktualisieren, wenn sich die Grenzen der Ansicht ändern, und der Ort, an dem dies getan werden soll, liegt innerhalb einer Überschreibung derlayoutSubviews()
Methode.Das Abrunden nur einiger Ecken eignet sich nicht für die automatische Größenänderung oder das automatische Layout.
Eine andere Möglichkeit besteht darin, regulär zu verwenden
cornerRadius
und die nicht gewünschten Ecken unter einer anderen Ansicht oder außerhalb der Grenzen der Übersicht auszublenden, um sicherzustellen, dass der Inhalt abgeschnitten ist.quelle
Um die Antwort und die Hinzufügung zu ergänzen , habe ich eine einfache,
UIView
in Swift wiederverwendbare Datei erstellt. Abhängig von Ihrem Anwendungsfall möchten Sie möglicherweise Änderungen vornehmen (vermeiden Sie das Erstellen von Objekten in jedem Layout usw.), aber ich wollte es so einfach wie möglich halten. Mit der Erweiterung können Sie diesUIImageView
einfacher auf andere Ansichten (z. B.) anwenden, wenn Sie keine Unterklassen mögen.So würden Sie es auf Folgendes anwenden
UIViewController
:quelle
Wenn Sie die Antwort von Stuart zusammenfassen, können Sie die folgende Methode anwenden:
Um eine abgerundete Ecke anzuwenden, tun Sie einfach:
quelle
Ich würde vorschlagen, die Maske einer Ebene zu definieren. Die Maske selbst sollte ein
CAShapeLayer
Objekt mit einem dedizierten Pfad sein. Sie können die nächste UIView-Erweiterung (Swift 4.2) verwenden:quelle