快速创建一个只有两个圆角的矩形?
Posted
技术标签:
【中文标题】快速创建一个只有两个圆角的矩形?【英文标题】:Create a rectangle with just two rounded corners in swift? 【发布时间】:2015-06-19 13:21:24 【问题描述】:我需要快速创建一个只有两个圆角的矩形(Objective C 代码也可以)。
目前我的代码正在使用
创建两个矩形CGPathCreateWithRoundedRect(CGRectMake(0, 0, 30, 60), 5, 5, nil);
和
CGPathCreateWithRoundedRect(CGRectMake(0, 0, 30, 60), 0, 0, nil);
并合并它们(有两个直角和两个圆角),但我对代码不满意,我很确定应该有更好的方法来做到这一点。
我是 ios 和图形开发和 swift 的新手。
【问题讨论】:
developer.apple.com/library/ios/documentation/UIKit/Reference/…:bezierPathWithRoundedRect:byRoundingCorners:cornerRadii:
像往常一样,*Swift 中发生了许多小的变化,例如常量的大写等。建议向下滚动到最新答案。
在这里查看我的答案,它将涵盖所有内容:- https://***.com/a/68342661/9863222
【参考方案1】:
更新:请参阅下面的 this answer 了解 Swift 4 / iOS 11,这要容易得多
这是一个快速的 Swift 3 扩展,您可以使用它来进行舍入和可选边框。
注意:如果您使用自动布局,您可能需要在视图受到约束后在 viewDidLayoutSubviews
或 layoutSubviews
等视图生命周期回调之一中调用它。
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)
【讨论】:
我在 UITextField 上使用它,但它改变了文本字段的宽度。为什么它会改变宽度(使用 Autolayout 设置)。 更新:只需要在viewDidLayoutSubviews
中调用扩展
@Onichan 我添加了一个fullyRound
方法,该方法也适用于自动布局视图,因为如果从viewDidLoad
代码调用框架则不会设置
@DaveG 适用于任何 UIView 子类(如 UIButton、UILabel、UITextField 等)
小心addBorder(mask:borderColor:borderWidth:)
方法,因为它总是添加一个新层。如果在空的 UIView 中使用 round(corners:radius:borderColor:borderWidth:)
方法调用 viewDidLayoutSubviews
或 layoutSubviews
5 次...该视图将有 5 个子层!【参考方案2】:
Swift 4+、iOS 11+
如果您已经有一个名为myView
的UIView
被引用为IBOutlet
,请尝试在ViewDidLoad()
或正在加载它的任何位置添加以下两行:
myView.layer.cornerRadius = 10
myView.layer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMaxYCorner]
您可以将数组[]
更改为MinX
、MinY
、MaxX
和MaxY
的任意组合以选择所需的角。上面的示例将底部的两个角倒圆。
这只是另一种方法,根据您的设计可能会更简单一些。
【讨论】:
大警告,此解决方案仅适用于 iOS 11+ 对于前两个角,您可以使用 view.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner] 非常感谢。虽然像 layerMinXMinYCorner 这样的命名在技术上是正确的,但我想知道为什么 Swift 有时必须那么丑【参考方案3】:在 Swift 2.3 中,您可以这样做
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
在Objective-C中你可以使用UIBezierPath
类方法
bezierPathWithRoundedRect:byRoundingCorners:cornerRadii:
示例实现-
// 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;
并将上述方法调用为-
[self setMaskTo:anyView byRoundingCorners:UIRectCornerBottomLeft | UIRectCornerBottomRight];
【讨论】:
我可以用你的回答解决我的问题。但只是好奇,因为我试图使用 UIBezierPath.addArcWithCenter 自己绘制圆角,并且开始和结束角度与developer.apple.com/library/ios/documentation/UIKit/Reference/… 上记录的所有角度都不匹配 你问的是使用起始角和结束角吗? #define RADIANS(degrees) ((degrees) / (180.0 / M_PI)) 并用作 - double startAngle = RADIANS(45);双 endAngle = RADIANS(135); 不适用于底部。即 bottomLeft & bottomRight【参考方案4】:Swift 3 - 有用的 UIView
扩展,当您需要对某些视图的特定角进行圆角处理时:
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
然后像这样使用它:
someView.round(corners: [.topLeft, .topRight], radius: 5)
【讨论】:
如何为这个视图设置边框或阴影? @VadlapalliMasthan 与您通常的方式相同。只需确保在圆角并应用阴影和边框之前设置视图的框架【参考方案5】:在 Sanjay 的出色答案的基础上,我为 Swift 2.3 编写了一个快速的 CALayer 扩展,以防您需要多次执行这种“只绕一些角落”的事情。
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
用法:
myView.layer.roundCorners([.TopLeft, .TopRight], radius: myCornerRadius)
Swift 3.0(在本例中,边界来自视图而不是图层。使用视图中的边界使此代码可以与 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
用法:
myView.layer.roundCorners(corners: [.topLeft, .topRight], radius: myCornerRadius, viewBounds: bounds)
【讨论】:
(好一个 - 像往常一样,Swift 有许多小的变化,例如常量的大写等) 对我来说,有时当我将顶角变圆时图像不会显示,所以我需要在之前的行中添加 myView.layoutIfNeeded()。 hi @satoukum - 在现代 Xcode 中处理该问题的正确方法如下面的回答所示,干杯【参考方案6】:仅限 iOS 11+ |你可以查看iOS使用统计here
说明
由于CACornerMask
rawValue 是UInt
,你知道CACornerMask
rawValue 是每个CACornerMask.Element
的总和rawValue
更具体地说:
左上角 (layerMinXMinYCorner
) = 1
TopRight (layerMaxXMinYCorner
) = 2
左下 (layerMinXMaxYCorner
) = 4
右下角 (layerMaxXMaxYCorner
) = 8
例如,如果您想要左上角和右上角角,您只需输入CACornerMask(rawValue: 3)
。
示例
下面是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
你可以这样使用它:
let myRect = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 50))
myRect.roundCorners(corners: [.topRight, .topLeft])
【讨论】:
【参考方案7】:这是您在 Swift 2.0
中所做的事情var maskPath = UIBezierPath(roundedRect: anyView.bounds,
byRoundingCorners: [.BottomLeft, .BottomRight],
cornerRadii: CGSize(width: 10.0, height: 10.0))
【讨论】:
不适用于底部。即 bottomLeft & bottomRight【参考方案8】:2021 年最新...
请注意,自从很久以前提出这个问题以来,语法/系统发生了很大变化!
import UIKit
@IBDesignable
class RoundedEnds: UIView
override func layoutSubviews()
super.layoutSubviews()
setup()
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
对于某些角落,只需将path
代码行更改为:
let path = UIBezierPath(
roundedRect: self.bounds,
byRoundingCorners: [.topLeft,.topRight],
cornerRadii: CGSize(width: r, height: r))
【讨论】:
【参考方案9】:斯威夫特 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
【讨论】:
如果我只想要四个角中的三个呢? [.bottomLeft, .bottomRight, .topRight] 不工作。【参考方案10】:更新了 iWasRobbed 的答案以使用 Swift 3.0 GM 版本:
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)
【讨论】:
【参考方案11】:extension CACornerMask
public static var leftBottom : CACornerMask get return .layerMinXMaxYCorner
public static var rightBottom : CACornerMask get return .layerMaxXMaxYCorner
public static var leftTop : CACornerMask get return .layerMaxXMinYCorner
public static var rightTop : CACornerMask get return .layerMinXMinYCorner
extension CALayer
func roundCorners(_ mask:CACornerMask,corner:CGFloat)
self.maskedCorners = mask
self.cornerRadius = corner
self.viewBack.layer.roundCorners([.leftBottom,.rightBottom], corner: 23)
【讨论】:
嗨,Mohammad Akbari,欢迎您。请考虑添加解释并正确格式化代码。【参考方案12】:总之,你可以像这样创建漂亮的扩展:
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
像这样使用它:
view.roundCorners([.topRight, .bottomRight], radius: 10)
这是所有角的值:
.topLeft .topRight .bottomLeft .bottomRight【讨论】:
【参考方案13】:view.layer.cornerRadius = 10.0
view.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMaxYCorner, .layerMinXMaxYCorner]
最好的方法!
【讨论】:
【参考方案14】:Swift 5:用于左上角和右上角的圆角。
yourView.layer.cornerRadius = 12
yourView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
【讨论】:
【参考方案15】:iWasRobbed 的 Objective-C 版本的回答:
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
【讨论】:
【参考方案16】:一个简单的hack可能如下。采取如下图示例中的视图。 Red View 将具有圆角,Yellow View(在 Red View 内)将防止圆角
现在为 Red View 编写以下代码。
self.myView.layer.cornerRadius = 15
确保不要将任何代码编写为 clipsToBounds = true 或 masksToBounds = true。
下图是结果
黄色视图的位置将决定哪 2 个角不会被圆角。希望这很容易实现。
【讨论】:
以上是关于快速创建一个只有两个圆角的矩形?的主要内容,如果未能解决你的问题,请参考以下文章
在 Swift 2.3 中使用 Bezier Path 和 Storyboard 绘制一个只有两个圆角的矩形 [重复]