Ich muss ein Rechteck mit nur zwei abgerundeten Ecken in Swift erstellen (Objective C-Code ist auch in Ordnung).
Im Moment erstellt mein Code zwei Rechtecke mit
CGPathCreateWithRoundedRect(CGRectMake(0, 0, 30, 60), 5, 5, nil);
und
CGPathCreateWithRoundedRect(CGRectMake(0, 0, 30, 60), 0, 0, nil);
und zusammenführen (um zwei rechtwinklige Ecken und zwei abgerundete zu haben), aber ich bin mit dem Code nicht zufrieden und ich bin mir ziemlich sicher, dass es viel bessere Möglichkeiten geben sollte.
Ich bin neu in iOS und grafischer Entwicklung und Swift.
In Swift 2.3 könnte man das durch machen
let maskPath = UIBezierPath(roundedRect: anyView.bounds,
byRoundingCorners: [.BottomLeft, .BottomRight],
cornerRadii: CGSize(width: 10.0, height: 10.0))
let shape = CAShapeLayer()
shape.path = maskPath.CGPath
view.layer.mask = shape
In Objective-C können Sie die Klassenmethode UIBezierPath
verwenden
bezierPathWithRoundedRect:byRoundingCorners:cornerRadii:
beispiel Implementierung
// set the corner radius to the specified corners of the passed container
- (void)setMaskTo:(UIView*)view byRoundingCorners:(UIRectCorner)corners
{
UIBezierPath *rounded = [UIBezierPath bezierPathWithRoundedRect:view.bounds
byRoundingCorners:corners
cornerRadii:CGSizeMake(10.0, 10.0)];
CAShapeLayer *shape = [[CAShapeLayer alloc] init];
[shape setPath:rounded.CGPath];
view.layer.mask = shape;
}
und rufen Sie die obige Methode als
[self setMaskTo:anyView byRoundingCorners:UIRectCornerBottomLeft | UIRectCornerBottomRight];
Hier ist eine schnelle Swift 3-Erweiterung, die Sie für Rundungen und optionale Rahmen verwenden können.
Anmerkung: Wenn Sie Autolayout verwenden, müssen Sie dies möglicherweise in einem der Callbacks des View-Lebenszyklus wie viewDidLayoutSubviews
oder layoutSubviews
aufrufen, nachdem die Sicht eingeschränkt wurde.
import UIKit
extension UIView {
/**
Rounds the given set of corners to the specified radius
- parameter corners: Corners to round
- parameter radius: Radius to round to
*/
func round(corners: UIRectCorner, radius: CGFloat) {
_ = _round(corners: corners, radius: radius)
}
/**
Rounds the given set of corners to the specified radius with a border
- parameter corners: Corners to round
- parameter radius: Radius to round to
- parameter borderColor: The border color
- parameter borderWidth: The border width
*/
func round(corners: UIRectCorner, radius: CGFloat, borderColor: UIColor, borderWidth: CGFloat) {
let mask = _round(corners: corners, radius: radius)
addBorder(mask: mask, borderColor: borderColor, borderWidth: borderWidth)
}
/**
Fully rounds an autolayout view (e.g. one with no known frame) with the given diameter and border
- parameter diameter: The view's diameter
- parameter borderColor: The border color
- parameter borderWidth: The border width
*/
func fullyRound(diameter: CGFloat, borderColor: UIColor, borderWidth: CGFloat) {
layer.masksToBounds = true
layer.cornerRadius = diameter / 2
layer.borderWidth = borderWidth
layer.borderColor = borderColor.cgColor;
}
}
private extension UIView {
@discardableResult func _round(corners: UIRectCorner, radius: CGFloat) -> CAShapeLayer {
let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
self.layer.mask = mask
return mask
}
func addBorder(mask: CAShapeLayer, borderColor: UIColor, borderWidth: CGFloat) {
let borderLayer = CAShapeLayer()
borderLayer.path = mask.path
borderLayer.fillColor = UIColor.clear.cgColor
borderLayer.strokeColor = borderColor.cgColor
borderLayer.lineWidth = borderWidth
borderLayer.frame = bounds
layer.addSublayer(borderLayer)
}
}
Swift 4+, iOS 11+
Wenn Sie bereits eine UIView
mit dem Namen myView
als IBOutlet
referenziert haben, fügen Sie die folgenden beiden Zeilen in ViewDidLoad()
oder wo auch immer sie geladen werden, hinzu:
myView.layer.cornerRadius = 10
myView.layer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMaxYCorner]
Sie können das Array []
in eine beliebige Kombination aus MinX
, MinY
, MaxX
und MaxY
ändern, um die gewünschten Ecken auszuwählen. Das obige Beispiel rundet die unteren beiden Ecken.
Dies ist nur ein weiterer Ansatz, der je nach Design etwas einfacher sein kann.
Swift 3 - Nützliche UIView
-Erweiterung, wenn Sie bestimmte Ecken einiger Ansichten abrunden müssen:
extension UIView {
func round(corners: UIRectCorner, radius: CGFloat) {
let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
self.layer.mask = mask
}
}
dann benutze es einfach so:
someView.round(corners: [.topLeft, .topRight], radius: 5)
Aufbauend auf Sanjays exzellenter Antwort habe ich eine schnelle CALayer-Erweiterung für Swift 2.3 geschrieben, falls Sie diese Art von "nur um einige Ecken" mehr als einmal tun müssen.
extension CALayer {
func roundCorners(corners: UIRectCorner, radius: CGFloat) {
let maskPath = UIBezierPath(roundedRect: bounds,
byRoundingCorners: corners,
cornerRadii: CGSize(width: radius, height: radius))
let shape = CAShapeLayer()
shape.path = maskPath.CGPath
mask = shape
}
}
Verwendungszweck:
myView.layer.roundCorners([.TopLeft, .TopRight], radius: myCornerRadius)
Swift 3.0 (In diesem Beispiel kamen die Grenzen aus der Ansicht und nicht aus der Ebene. Durch die Verwendung der Grenzen aus der Ansicht können Sie diesen Code für die Arbeit mit Ansichten in einer UITableViewCell verwenden.):
func roundCorners(corners: UIRectCorner, radius: CGFloat, viewBounds: CGRect) {
let maskPath = UIBezierPath(roundedRect: viewBounds,
byRoundingCorners: corners,
cornerRadii: CGSize(width: radius, height: radius))
let shape = CAShapeLayer()
shape.path = maskPath.cgPath
mask = shape
}
Verwendungszweck:
myView.layer.roundCorners(corners: [.topLeft, .topRight], radius: myCornerRadius, viewBounds: bounds)
Folgendes tun Sie in Swift 2.0
var maskPath = UIBezierPath(roundedRect: anyView.bounds,
byRoundingCorners: [.BottomLeft, .BottomRight],
cornerRadii: CGSize(width: 10.0, height: 10.0))
@IBDesignable
class RoundedEnds: UIView {
override func layoutSubviews() { setup() } // "layoutSubviews" is best
func setup() {
let r = self.bounds.size.height / 2
let path = UIBezierPath(roundedRect: self.bounds, cornerRadius:r)
let mask = CAShapeLayer()
mask.path = path.cgPath
self.layer.mask = mask
}
}
Für nur einige Ecken wechseln Sie einfach zu:
roundedRect: self.bounds,
byRoundingCorners: [.topLeft, .topRight],
cornerRadii: CGSize(width: r, height: r)
Beachten Sie, dass Swift wie üblich viele kleine Änderungen vorgenommen hat, z. B. die Großschreibung von Konstanten usw.
Swift 4:
let maskPath = UIBezierPath(
roundedRect: view.bounds,
byRoundingCorners: [.allCorners],
cornerRadii: CGSize(width: 10.0, height: 10.0)
)
let shape = CAShapeLayer()
shape.path = maskPath.cgPath
view.layer.mask = shape
Die Antwort von iWasRobbed wurde aktualisiert, um mit der Version Swift 3.0 GM zu arbeiten:
import UIKit
extension UIView {
/**
Rounds the given set of corners to the specified radius
- parameter corners: Corners to round
- parameter radius: Radius to round to
*/
func round(corners: UIRectCorner, radius: CGFloat) {
_round(corners: corners, radius: radius)
}
/**
Rounds the given set of corners to the specified radius with a border
- parameter corners: Corners to round
- parameter radius: Radius to round to
- parameter borderColor: The border color
- parameter borderWidth: The border width
*/
func round(corners: UIRectCorner, radius: CGFloat, borderColor: UIColor, borderWidth: CGFloat) {
let mask = _round(corners: corners, radius: radius)
addBorder(mask: mask, borderColor: borderColor, borderWidth: borderWidth)
}
/**
Fully rounds an autolayout view (e.g. one with no known frame) with the given diameter and border
- parameter diameter: The view's diameter
- parameter borderColor: The border color
- parameter borderWidth: The border width
*/
func fullyRound(diameter: CGFloat, borderColor: UIColor, borderWidth: CGFloat) {
layer.masksToBounds = true
layer.cornerRadius = diameter / 2
layer.borderWidth = borderWidth
layer.borderColor = borderColor.cgColor;
}
}
private extension UIView {
@discardableResult func _round(corners: UIRectCorner, radius: CGFloat) -> CAShapeLayer {
let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
self.layer.mask = mask
return mask
}
func addBorder(mask: CAShapeLayer, borderColor: UIColor, borderWidth: CGFloat) {
let borderLayer = CAShapeLayer()
borderLayer.path = mask.path
borderLayer.fillColor = UIColor.clear.cgColor
borderLayer.strokeColor = borderColor.cgColor
borderLayer.lineWidth = borderWidth
borderLayer.frame = bounds
layer.addSublayer(borderLayer)
}
}
Objective-C-Version der Antwort von iWasRobbed:
UIView + RoundCorners.h
#import <UIKit/UIKit.h>
@interface UIView (RoundCorners)
/**
Rounds the given set of corners to the specified radius
- parameter corners: Corners to round
- parameter radius: Radius to round to
*/
- (void)roundCorners:(UIRectCorner)corners radius:(CGFloat)radius;
/**
Rounds the given set of corners to the specified radius with a border
- parameter corners: Corners to round
- parameter radius: Radius to round to
- parameter borderColor: The border color
- parameter borderWidth: The border width
*/
- (void)roundCorners:(UIRectCorner)corners radius:(CGFloat)radius borderColor:(UIColor *)borderColor borderWidth:(CGFloat)borderWidth;
/**
Fully rounds an autolayout view (e.g. one with no known frame) with the given diameter and border
- parameter diameter: The view's diameter
- parameter borderColor: The border color
- parameter borderWidth: The border width
*/
- (void)fullyRoundWithDiameter:(CGFloat)diameter borderColor:(UIColor *)borderColor borderWidth:(CGFloat)borderWidth;
@end
UIView + RoundCorners.m
#import "UIView+RoundCorners.h"
@implementation UIView (RoundCorners)
- (void)roundCorners:(UIRectCorner)corners radius:(CGFloat)radius {
[self _roundCorners:corners radius:radius];
}
- (void)roundCorners:(UIRectCorner)corners radius:(CGFloat)radius borderColor:(UIColor *)borderColor borderWidth:(CGFloat)borderWidth {
CAShapeLayer *mask = [self _roundCorners:corners radius:radius];
[self addBorderWithMask:mask borderColor:borderColor borderWidth:borderWidth];
}
- (void)fullyRoundWithDiameter:(CGFloat)diameter borderColor:(UIColor *)borderColor borderWidth:(CGFloat)borderWidth {
self.layer.masksToBounds = YES;
self.layer.cornerRadius = diameter / 2;
self.layer.borderWidth = borderWidth;
self.layer.borderColor = borderColor.CGColor;
}
- (CAShapeLayer *)_roundCorners:(UIRectCorner)corners radius:(CGFloat)radius {
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:corners cornerRadii:CGSizeMake(radius, radius)];
CAShapeLayer *mask = [CAShapeLayer layer];
mask.path = path.CGPath;
self.layer.mask = mask;
return mask;
}
- (void)addBorderWithMask:(CAShapeLayer *)mask borderColor:(UIColor *)borderColor borderWidth:(CGFloat)borderWidth {
CAShapeLayer *borderLayer = [CAShapeLayer layer];
borderLayer.path = mask.path;
borderLayer.fillColor = UIColor.clearColor.CGColor;
borderLayer.strokeColor = borderColor.CGColor;
borderLayer.lineWidth = borderWidth;
borderLayer.frame = self.bounds;
[self.layer addSublayer:borderLayer];
}
@end
Ein einfacher Hack könnte sein: Nehmen Sie Ansichten wie im folgenden Beispiel auf. Rote Ansicht hat abgerundete Ecken und Gelbe Ansicht (innerhalb der roten Ansicht) verhindert, dass die Ecken abgerundet werden
Schreiben Sie nun den folgenden Code für Red View.
self.myView.layer.cornerRadius = 15
Stellen Sie sicher, dass Sie keinen Code als clipsToBounds = true oder masksToBounds = true schreiben.
Unteres Bild ist das Ergebnis
Die Platzierung von Yellow View entscheidet, welche 2 Ecken nicht gerundet werden. Hoffe das ist einfach umzusetzen.
Zusammenfassend können Sie eine hübsche Erweiterung wie diese erstellen:
extension UIView {
func roundCorners(_ corners: UIRectCorner, radius: Double) {
let maskPath = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let shape = CAShapeLayer()
shape.path = maskPath.cgPath
layer.mask = shape
}
}
Benutze es so:
view.roundCorners([.topRight, .bottomRight], radius: 10)
Hier sind alle Eckwerte:
iOS 11+ Nur | Sie können iOS-Nutzungsstatistiken überprüfen hier
Da CACornerMask
rawValue eine UInt
ist, müssen Sie jetzt, dass CACornerMask
rawValue die Summe jedes CACornerMask.Element
rawValue ist.
Genauer:
layerMinXMinYCorner
) = 1layerMaxXMinYCorner
) = 2layerMinXMaxYCorner
) = 4layerMaxXMaxYCorner
) = 8Wenn Sie beispielsweise top left und top right wünschen, können Sie einfach CACornerMask(rawValue: 3)
eingeben.
Nachfolgend eine einfache Erweiterung einer UIView
extension UIView {
enum Corner:Int {
case bottomRight = 0,
topRight,
bottomLeft,
topLeft
}
private func parseCorner(corner: Corner) -> CACornerMask.Element {
let corners: [CACornerMask.Element] = [.layerMaxXMaxYCorner, .layerMaxXMinYCorner, .layerMinXMaxYCorner, .layerMinXMinYCorner]
return corners[corner.rawValue]
}
private func createMask(corners: [Corner]) -> UInt {
return corners.reduce(0, { (a, b) -> UInt in
return a + parseCorner(corner: b).rawValue
})
}
func roundCorners(corners: [Corner], amount: CGFloat = 5) {
layer.cornerRadius = amount
let maskedCorners: CACornerMask = CACornerMask(rawValue: createMask(corners: corners))
layer.maskedCorners = maskedCorners
}
}
Sie können dies wie folgt verwenden:
let myRect = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 50))
myRect.roundCorners(corners: [.topRight, .topLeft])