如何仅为图层的左下角、右下角和左上角设置圆角?

90

如何仅为TextView的左下角、右下角和左上角设置圆角?

let rectShape = CAShapeLayer()
rectShape.backgroundColor = UIColor.redColor().CGColor
rectShape.bounds = messages.frame
rectShape.position = messages.center
rectShape.path = UIBezierPath(roundedRect: messages.bounds, byRoundingCorners: .BottomLeft | .TopRight, cornerRadii: CGSize(width: 20, height: 20)).CGPath

messages.layer.addSublayer(rectShape)

这段代码创建了两个矩形,但我不知道为什么。


在这段代码中,你不是添加遮罩,而是将rectshape作为消息textView的子层添加。 - Shailesh Chandavar
Zept,这有意义吗? - Shailesh Chandavar
https://dev59.com/Hl0Z5IYBdhLWcg3wpRlW - Kirit Modi
13个回答

221

(Swift 4/iOS 11) 简单说,底部:

yourView.clipsToBounds = true 
yourView.layer.cornerRadius = 10
yourView.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMinXMaxYCorner]

向上:

yourView.clipsToBounds = true 
yourView.layer.cornerRadius = 10
yourView.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner]

在你的情况下:

yourView.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMinXMaxYCorner, .layerMinXMinYCorner]

希望这能帮到你 :)


simple and concise. - Hudi Ilfeld
对我有用。谢谢Fabio! - Ahmad Ismail
CACornerMask扩展常量,以便人类理解:http://gist.github.com/derekleerock/19a767c528b53ffa381a51c49f220595 - Derek Lee

82

您只需按照下面所示的方式遮罩图层:

针对 Swift 3:

let rectShape = CAShapeLayer()
rectShape.bounds = self.myView.frame
rectShape.position = self.myView.center
rectShape.path = UIBezierPath(roundedRect: self.myView.bounds, byRoundingCorners: [.bottomLeft , .bottomRight , .topLeft], cornerRadii: CGSize(width: 20, height: 20)).cgPath

self.myView.layer.backgroundColor = UIColor.green.cgColor
//Here I'm masking the textView's layer with rectShape layer
self.myView.layer.mask = rectShape

较低版本:

let rectShape = CAShapeLayer()
rectShape.bounds = self.myView.frame
rectShape.position = self.myView.center
rectShape.path = UIBezierPath(roundedRect: self.myView.bounds, byRoundingCorners: .BottomLeft | .BottomRight | .TopLeft, cornerRadii: CGSize(width: 20, height: 20)).CGPath

self.myView.layer.backgroundColor = UIColor.greenColor().CGColor
//Here I'm masking the textView's layer with rectShape layer
self.myView.layer.mask = rectShape

2
抱歉,我想再问一个问题。我无法将角落圆形化到右侧。.TopRight和.ButtonRight不起作用。 - Zept
1
只需将此代码添加到新控制器中并检查一次,因为可能是您的自动布局存在问题。对我而言,它可以正常工作。 - Shailesh Chandavar
7
我认为 byRoundingCorners 接受一个数组作为参数,因此在上面的例子中应该是:byRoundingCorners: [.BottomLeft, .BottomRight, .TopLeft] - Jan Molak
6
不工作于底部,即底部左侧和底部右侧。 - user1673099
1
在iPhone8Plus中,文本字段圆角左上角和左下角之后留出右侧空间。 - puja
显示剩余6条评论

65

Swift 3

extension UIView {
    func roundCorners(_ corners:UIRectCorner, radius: CGFloat) {
    let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
    let mask = CAShapeLayer()
    mask.path = path.cgPath
    self.layer.mask = mask
  }
}

使用方法

YourView.roundCorners([.topLeft, .bottomLeft], radius: 10)

18
不工作于底部。即 bottomLeft 和 bottomRight。 - user1673099
非常完美地运作,无论在哪个角落。谢谢! - Harsha
@Harsha 很高兴能帮助你。 - Museer Ahamad Ansari
2
我遇到了一个关于右上角和右下角的问题。:( - tBug
3
我遇到了类似的问题,即右上角和右下角无法正常工作。我通过在视图控制器的viewDidLayoutSubviews方法和表格视图单元格的layoutSubviews方法中调用它来解决了这个问题。这对我起作用了。 - vinodonkar
显示剩余4条评论

29

更好的答案是适用于iOS 11和iOS 10底部角落的:

 if #available(iOS 11.0, *){
        view.clipsToBounds = true
        view.layer.cornerRadius = 10
        view.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMinXMaxYCorner]
    }else{
       let rectShape = CAShapeLayer()
       rectShape.bounds = view.frame
       rectShape.position = view.center
       rectShape.path = UIBezierPath(roundedRect: view.bounds,    byRoundingCorners: [.bottomLeft , .bottomRight], cornerRadii: CGSize(width: 20, height: 20)).cgPath
      view.layer.backgroundColor = UIColor.green.cgColor
      view.layer.mask = rectShape
  }

如果在iOS 10及以下版本中无法正常工作,尝试在你的viewcontroller类的viewDidLayoutSubviews()方法中按照如下方式运行代码

在此情况下,如果iOS 10及以下版本无法正常工作,请尝试像这样在viewcontroller类的viewDidLayoutSubviews()方法中运行代码。

override func viewDidLayoutSubviews() {
    if #available(iOS 11.0, *){
    }else{
       let rectShape = CAShapeLayer()
       rectShape.bounds = view.frame
       rectShape.position = view.center
       rectShape.path = UIBezierPath(roundedRect: view.bounds,    byRoundingCorners: [.bottomLeft , .bottomRight], cornerRadii: CGSize(width: 20, height: 20)).cgPath
       view.layer.backgroundColor = UIColor.green.cgColor
       view.layer.mask = rectShape
}

2
在iOS 11上完美运行。 - Niraj
完美地适用于iOS 10。它在顶部和右上角没有起作用,但将代码移动到viewDidLayoutSubViews中解决了问题。谢谢 - AymAn AbuOmar

28
Swift 4+
func roundCorners(with CACornerMask: CACornerMask, radius: CGFloat) {
    self.layer.cornerRadius = radius
    self.layer.maskedCorners = [CACornerMask]
}

如何使用
//Top right
roundCorners(with: [.layerMaxXMinYCorner], radius: 20)

//Top left
roundCorners(with: [.layerMinXMinYCorner], radius: 20)

//Bottom right
roundCorners(with: [.layerMaxXMaxYCorner], radius: 20)

//Bottom left 
roundCorners(with: [.layerMinXMaxYCorner], radius: 20)

或者

另一种方法是使用 CACornerMask

extension UIView{
    
    enum RoundCornersAt{
        case topRight
        case topLeft
        case bottomRight
        case bottomLeft
    }
    
        //multiple corners using CACornerMask
    func roundCorners(corners:[RoundCornersAt], radius: CGFloat) {
        self.layer.cornerRadius = radius
        self.layer.maskedCorners = [
            corners.contains(.topRight) ? .layerMaxXMinYCorner:.init(),
            corners.contains(.topLeft) ? .layerMinXMinYCorner:.init(),
            corners.contains(.bottomRight) ? .layerMaxXMaxYCorner:.init(),
            corners.contains(.bottomLeft) ? .layerMinXMaxYCorner:.init(),
        ]
    }
    
}

您可以像下面这样使用。
myView.roundCorners(corners: [.topLeft,.bottomLeft], radius: 20)

或者

使用UIRectCorner实现多个角落

func roundedCorners(corners : UIRectCorner, radius : CGFloat) {
    let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
    let mask = CAShapeLayer()
    mask.path = path.cgPath
    layer.mask = mask
}

如何使用
roundedCorners(corners: [.topLeft, .topRight], radius: 20)

这是我找到的最佳答案。谢谢。 - Arshad Shaik

11

针对子视图和弹出窗口 [Swift 5]

override func layoutSublayers(of layer: CALayer) {
    searchBarPopup.clipsToBounds = true
    searchBarPopup.layer.cornerRadius = 10
    searchBarPopup.layer.maskedCorners = [ .layerMaxXMinYCorner, .layerMinXMinYCorner]
}

输出:

在此输入图片描述


请添加一些解释,以帮助新手理解您所写的内容。 - sayalok

10

Swift 4

override func viewDidLoad() {
    let topRight = UIView(frame: CGRect(x: 120, y: 200, width: 120, height: 120))
    topRight.roundedTop()
    topRight.backgroundColor = .red
    self.view.center = topRight.center
    self.view.addSubview(topRight)
    super.viewDidLoad()
}

输出:

在此输入图像描述

UIView Swift 4的扩展程序:参考链接


9

这里是适用于iOS 11+的扩展程序。

 import Foundation
 import UIKit

 extension UIView {

   func roundCorners(_ corners: CACornerMask, radius: CGFloat, borderColor: UIColor, borderWidth: CGFloat) {
       self.layer.maskedCorners = corners
       self.layer.cornerRadius = radius
       self.layer.borderWidth = borderWidth
       self.layer.borderColor = borderColor.cgColor
    
   }

 }

使用方法:

self.yourView.roundCorners([.layerMaxXMaxYCorner, .layerMaxXMinYCorner], radius: 20.0, borderColor: UIColor.green, borderWidth: 1)

Swift 5+

view.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMaxXMinYCorner]

9
  1. 将RoundedCornerView.swift文件添加到您的项目中
  2. 在您的ViewController中添加一个UIView
  3. 在Identity Inspector中更改Custom Class为RoundedCornerView
  4. 进入Attribute Inspector选择Corner Radius(CGFloat)以及您想要圆角的角落。

rounded corner view

RoundedCornerView.swift

import UIKit

@IBDesignable
class RoundedCornerView: UIView {

    var cornerRadiusValue : CGFloat = 0
    var corners : UIRectCorner = []

    @IBInspectable public var cornerRadius : CGFloat {
        get {
            return cornerRadiusValue
        }
        set {
            cornerRadiusValue = newValue
        }
    }

    @IBInspectable public var topLeft : Bool {
        get {
            return corners.contains(.topLeft)
        }
        set {
            setCorner(newValue: newValue, for: .topLeft)
        }
    }

    @IBInspectable public var topRight : Bool {
        get {
            return corners.contains(.topRight)
        }
        set {
            setCorner(newValue: newValue, for: .topRight)
        }
    }

    @IBInspectable public var bottomLeft : Bool {
        get {
            return corners.contains(.bottomLeft)
        }
        set {
            setCorner(newValue: newValue, for: .bottomLeft)
        }
    }

    @IBInspectable public var bottomRight : Bool {
        get {
            return corners.contains(.bottomRight)
        }
        set {
            setCorner(newValue: newValue, for: .bottomRight)
        }
    }

    func setCorner(newValue: Bool, for corner: UIRectCorner) {
        if newValue {
            addRectCorner(corner: corner)
        } else {
            removeRectCorner(corner: corner)
        }
    }

    func addRectCorner(corner: UIRectCorner) {
        corners.insert(corner)
        updateCorners()
    }

    func removeRectCorner(corner: UIRectCorner) {
        if corners.contains(corner) {
            corners.remove(corner)
            updateCorners()
        }
    }

    func updateCorners() {
        let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: cornerRadiusValue, height: cornerRadiusValue))
        let mask = CAShapeLayer()
        mask.path = path.cgPath
        self.layer.mask = mask
    }

}

GitHub链接:RoundedCornerView


感谢这个库,它起作用了,但是在Storyboard中更新不太快,我们需要打开和关闭属性,才能使其更新。 - Arshad Shaik
在Storyboard中可以正常工作,但在设备上只对左上角有效。为什么? - Mahdi Moqadasi
1
@MahdiMoqadasi 如果您的设备宽度与模拟器设备不同,则可能无法在实际设备上显示。更好的解决方案是在viewDidLayoutSubviews()函数中设置所有要圆角的角为true。例如,在viewDidLayoutSubviews()函数内编写以下内容: roundedView.topLeft = true roundedView.topRight = true它将根据您视图的宽度重新绘制。希望能帮到您。 - kazi.munshimun

5
我想到的最好的解决方案是所有以上解决方案中最好的一个。
extension UIView {
    func roundCorners(_ corners: UIRectCorner, radius: CGFloat) {
        if #available(iOS 11, *) {
            var cornerMask = CACornerMask()
            if(corners.contains(.topLeft)){
                cornerMask.insert(.layerMinXMinYCorner)
            }
            if(corners.contains(.topRight)){
                cornerMask.insert(.layerMaxXMinYCorner)
            }
            if(corners.contains(.bottomLeft)){
                cornerMask.insert(.layerMinXMaxYCorner)
            }
            if(corners.contains(.bottomRight)){
                cornerMask.insert(.layerMaxXMaxYCorner)
            }
            self.layer.cornerRadius = radius
            self.layer.maskedCorners = cornerMask

        } else {
            let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
            let mask = CAShapeLayer()
            mask.path = path.cgPath
            self.layer.mask = mask
        }
    }
}

我相信通过这种方式实现在选择方面更加容易。

view.roundCorners([.bottomLeft, .bottomRight, .topLeft], radius: 16)

我刚刚根据这里提供的所有答案,想出了一个简单易用的扩展程序。很高兴听到它对你有所帮助。 - kshitiz_7

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接