可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I need to create a rectangle that have just two rounded corners in swift (Objective C code also ok).
At the moment my code is creating two rectangles with
CGPathCreateWithRoundedRect(CGRectMake(0, 0, 30, 60), 5, 5, nil);
and
CGPathCreateWithRoundedRect(CGRectMake(0, 0, 30, 60), 0, 0, nil);
and merging them (to have two right angle corners and two rounded ones) but I am not happy with the code and I am pretty sure there should be much better ways to do it.
I am new to iOS and graphical development and swift.
回答1:
In Swift 2.3 you could do so by
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 you could use the UIBezierPath
class method
bezierPathWithRoundedRect:byRoundingCorners:cornerRadii:
example implementation-
// 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;
}
and call the above method as-
[self setMaskTo:anyView byRoundingCorners:UIRectCornerBottomLeft | UIRectCornerBottomRight];
回答2:
Here's a quick Swift 3 extension you can use to do rounding and optional borders.
Note: if you're using autolayout, you may need to call this in one of the view lifecycle callbacks like viewDidLayoutSubviews
or layoutSubviews
after the view has been constrained.
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)
}
}
回答3:
Swift 3 - Useful UIView
extension when you need to round specific corners of some views:
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
}
}
then just use it like this:
someView.round(corners: [.topLeft, .topRight], radius: 5)
回答4:
Swift 4+, iOS 11+
If you already have a UIView
named myView
referenced as an IBOutlet
, try adding the following two lines in ViewDidLoad()
or wherever it's being loaded:
myView.layer.cornerRadius = 10
myView.layer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMaxYCorner]
You can change the array []
to any combination of MinX
, MinY
, MaxX
, and MaxY
to select the desired corners. The above example rounds the bottom two corners.
This is just another approach, can be a bit simpler depending on your design.
回答5:
Building on top of Sanjay's excellent answer, I wrote a quick CALayer extension for Swift 2.3, in case you need to do this sort of "only round some corners" thing more than once.
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
}
}
Usage:
myView.layer.roundCorners([.TopLeft, .TopRight], radius: myCornerRadius)
Swift 3.0 (In this example the bounds came from the view not from the layer. Using the bounds from the view make this code to work with views in a UITableViewCell.):
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
}
Usage:
myView.layer.roundCorners(corners: [.topLeft, .topRight], radius: myCornerRadius, viewBounds: bounds)
回答6:
Here is what you do in Swift 2.0
var maskPath = UIBezierPath(roundedRect: anyView.bounds,
byRoundingCorners: [.BottomLeft, .BottomRight],
cornerRadii: CGSize(width: 10.0, height: 10.0))
回答7:
2017...
@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
}
}
For only some corners, just change to:
roundedRect: self.bounds,
byRoundingCorners: [.topLeft, .topRight],
cornerRadii: CGSize(width: r, height: r)
Note that as usual there have been many small changes in Swift, eg capitalization of constants, etc.
回答8:
Updated iWasRobbed's answer to work with the Swift 3.0 GM version:
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)
}
}
回答9:
Objective-C version of iWasRobbed's answer:
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
回答10:
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