iOS(swift)设置圆角属性

设置圆角

假设现在圆角视图非常多(比如在 UICollectionView 中),那么如何为视图高效的添加圆角呢?网上的教程大多没有说全,因为这个事要分两种情况考虑。为普通的 UIView 设置圆角,和为 UIImageView 设置圆角的原理截然不同。

有一种做法是这样的,这种写法试图实现 cornerRadius = 3 的效果:

override func drawRect(rect: CGRect) { let maskPath = UIBezierPath(roundedRect: rect, byRoundingCorners: .AllCorners, cornerRadii: CGSize(width: 3, height: 3)) let maskLayer = CAShapeLayer() maskLayer.frame = self.bounds maskLayer.path = maskPath.CGPath self.layer.mask = maskLayer }

不过这是一种错的离谱的写法!

首先,我们应该尽量避免重写 drawRect 方法。不恰当的使用这个方法会导致内存暴增。举个例子,iPhone6 上与屏幕等大的 UIView,即使重写一个空的 drawRect 方法,它也至少占用 750 * 1134 * 4 字节 ≈ 3.4 Mb 的内存。在 内存恶鬼drawRect 及其后续中,作者详细介绍了其中原理,据他测试,在 iPhone6 上空的、与屏幕等大的视图重写 drawRect 方法会消耗 5.2 Mb 内存。总之,能避免重写 drawRect 方法就尽可能避免。

其次,这种方法本质上是用遮罩层 mask 来实现,因此同样无可避免的会导致离屏渲染。我试着将此前 34 个视图的圆角改用这种方法实现,结果 fps 掉到 11 左右。已经属于卡出翔的节奏了。

忘掉这种写法吧,下面介绍正确的高效设置圆角的姿势。

为 UIView 添加圆角

这种做法的原理是手动画出圆角。虽然我们之前说过,为普通的视图直接设置 cornerRadius 属性即可。但万一不可避免的需要使用 masksToBounds,就可以使用下面这种方法,它的核心代码如下:

func kt_drawRectWithRoundedCorner(radius radius: CGFloat,
                                  borderWidth: CGFloat,
                                  backgroundColor: UIColor,
                                  borderColor: UIColor) -> UIImage { UIGraphicsBeginImageContextWithOptions(sizeToFit, false, UIScreen.mainScreen().scale) let context = UIGraphicsGetCurrentContext() CGContextMoveToPoint(context, 开始位置); // 开始坐标右边开始 CGContextAddArcToPoint(context, x1, y1, x2, y2, radius); // 这种类型的代码重复四次 CGContextDrawPath(UIGraphicsGetCurrentContext(), .FillStroke) let output = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return output }

这个方法返回的是 UIImage,也就是说我们利用 Core Graphics 自己画出了一个圆角矩形。除了一些必要的代码外,最核心的就是 CGContextAddArcToPoint 函数。它中间的四个参数表示曲线的起点和终点坐标,最后一个参数表示半径。调用了四次函数后,就可以画出圆角矩形。最后再从当前的绘图上下文中获取图片并返回。

有了这个图片后,我们创建一个 UIImageView 并插入到视图层级的底部:

extension UIView {
    func kt_addCorner(radius radius: CGFloat, borderWidth: CGFloat, backgroundColor: UIColor, borderColor: UIColor) { let imageView = UIImageView(image: kt_drawRectWithRoundedCorner(radius: radius, borderWidth: borderWidth, backgroundColor: backgroundColor, borderColor: borderColor)) self.insertSubview(imageView, atIndex: 0) } }

完整的代码可以在项目中找到,使用时,你只需要这样写:

let view = UIView(frame: CGRectMake(1,2,3,4)) view.kt_addCorner(radius: 6)

为 UIImageView 添加圆角

相比于上面一种实现方法,为 UIImageView 添加圆角更为常用。它的实现思路是直接截取图片:

extension UIImage {
    func kt_drawRectWithRoundedCorner(radius radius: CGFloat, _ sizetoFit: CGSize) -> UIImage { let rect = CGRect(origin: CGPoint(x: 0, y: 0), size: sizetoFit) UIGraphicsBeginImageContextWithOptions(rect.size, false, UIScreen.mainScreen().scale) CGContextAddPath(UIGraphicsGetCurrentContext(), UIBezierPath(roundedRect: rect, byRoundingCorners: UIRectCorner.AllCorners, cornerRadii: CGSize(width: radius, height: radius)).CGPath) CGContextClip(UIGraphicsGetCurrentContext()) self.drawInRect(rect) CGContextDrawPath(UIGraphicsGetCurrentContext(), .FillStroke) let output = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return output } }

圆角路径直接用贝塞尔曲线绘制,一个意外的 bonus 是还可以选择哪几个角有圆角效果。这个函数的效果是将原来的 UIImage 剪裁出圆角。配合着这函数,我们可以为 UIImageView 拓展一个设置圆角的方法:

extension UIImageView {
    /**
     / !!!只有当 imageView 不为nil 时,调用此方法才有效果

     :param: radius 圆角半径
     */
    override func kt_addCorner(radius radius: CGFloat) { self.image = self.image?.kt_drawRectWithRoundedCorner(radius: radius, self.bounds.size) } }

完整的代码可以在项目中找到,使用时,你只需要这样写:

let imageView = let imgView1 = UIImageView(image: UIImage(name: "")) imageView.kt_addCorner(radius: 6)

提醒

无论使用上面哪种方法,你都需要小心使用背景颜色。因为此时我们没有设置 masksToBounds,因此超出圆角的部分依然会被显示。因此,你不应该再使用背景颜色,可以在绘制圆角矩形时设置填充颜色来达到类似效果。

在为 UIImageView 添加圆角时,请确保 image 属性不是 nil,否则这个设置将会无效。

    1. 如果能够只用 cornerRadius 解决问题,就不用优化。
    2. 如果必须设置 masksToBounds,可以参考圆角视图的数量,如果数量较少(一页只有几个)也可以考虑不用优化。
    3. UIImageView 的圆角通过直接截取图片实现,其它视图的圆角可以通过 Core Graphics 画出圆角矩形实现。

转载于:https://www.cnblogs.com/Bose-EinsteinCondensation/p/6402989.html

你可能感兴趣的:(iOS(swift)设置圆角属性)