【问题标题】:Different cornerRadius for each corner Swift 3 - iOS每个角落的不同cornerRadius Swift 3 - iOS
【发布时间】:2017-03-22 18:52:37
【问题描述】:

我想在 Swift -3 中为视图设置不同的角半径,我可以将每个角的半径设置为与以下帖子中提到的值相同的值,how to set cornerRadius for only top-left and top-right corner of a UIView?

有没有办法可以按以下格式设置圆角半径? 左上角半径:18 右上方半径:18 右下角半径:3 半径左下角:18

【问题讨论】:

标签: ios swift3 cornerradius


【解决方案1】:

在 iOS 11 之后执行此操作的最佳方式,这样看起来更流畅。

 func roundCorners(_ corners: UIRectCorner, radius: CGFloat) {
        clipsToBounds = true
        layer.cornerRadius = radius
        layer.maskedCorners = CACornerMask(rawValue: corners.rawValue)
  }

原始答案:https://stackoverflow.com/a/50289822/4206186

【讨论】:

    【解决方案2】:

    基于@Kirill Dobryakov 的略微改进和简化的答案。曲线可能会留下非常小的但明显的不规则性,当您查看它并且您知道它不是理想的圆形时(尝试例如查看边 40 和半径 20)。我不知道这怎么可能,但无论如何,最可靠的方法是使用弧线来制作理想的圆角,以及为您提供@IBDesigneable 组件:

    extension UIBezierPath {
    
        convenience init(shouldRoundRect rect: CGRect, topLeftRadius: CGFloat, topRightRadius: CGFloat, bottomLeftRadius: CGFloat, bottomRightRadius: CGFloat){
    
            self.init()
    
            let path = CGMutablePath()
    
            let topLeft = rect.origin
            let topRight = CGPoint(x: rect.maxX, y: rect.minY)
            let bottomRight = CGPoint(x: rect.maxX, y: rect.maxY)
            let bottomLeft = CGPoint(x: rect.minX, y: rect.maxY)
    
            if topLeftRadius != 0 {
                path.move(to: CGPoint(x: topLeft.x + topLeftRadius, y: topLeft.y))
            } else {
                path.move(to: topLeft)
            }
    
            if topRightRadius != 0 {
                path.addLine(to: CGPoint(x: topRight.x - topRightRadius, y: topRight.y))
                path.addArc(tangent1End: topRight, tangent2End: CGPoint(x: topRight.x, y: topRight.y + topRightRadius), radius: topRightRadius)
            }
            else {
                path.addLine(to: topRight)
            }
    
            if bottomRightRadius != 0 {
                path.addLine(to: CGPoint(x: bottomRight.x, y: bottomRight.y - bottomRightRadius))
                path.addArc(tangent1End: bottomRight, tangent2End: CGPoint(x: bottomRight.x - bottomRightRadius, y: bottomRight.y), radius: bottomRightRadius)
            }
            else {
                path.addLine(to: bottomRight)
            }
    
            if bottomLeftRadius != 0 {
                path.addLine(to: CGPoint(x: bottomLeft.x + bottomLeftRadius, y: bottomLeft.y))
                path.addArc(tangent1End: bottomLeft, tangent2End: CGPoint(x: bottomLeft.x, y: bottomLeft.y - bottomLeftRadius), radius: bottomLeftRadius)
            }
            else {
                path.addLine(to: bottomLeft)
            }
    
            if topLeftRadius != 0 {
                path.addLine(to: CGPoint(x: topLeft.x, y: topLeft.y + topLeftRadius))
                path.addArc(tangent1End: topLeft, tangent2End: CGPoint(x: topLeft.x + topLeftRadius, y: topLeft.y), radius: topLeftRadius)
            }
            else {
                path.addLine(to: topLeft)
            }
    
            path.closeSubpath()
            cgPath = path
        }
    }
    
    
    
    @IBDesignable
    open class VariableCornerRadiusView: UIView  {
    
        private func applyRadiusMaskFor() {
            let path = UIBezierPath(shouldRoundRect: bounds, topLeftRadius: topLeftRadius, topRightRadius: topRightRadius, bottomLeftRadius: bottomLeftRadius, bottomRightRadius: bottomRightRadius)
            let shape = CAShapeLayer()
            shape.path = path.cgPath
            layer.mask = shape
        }
    
        @IBInspectable
        open var topLeftRadius: CGFloat = 0 {
            didSet { setNeedsLayout() }
        }
    
        @IBInspectable
        open var topRightRadius: CGFloat = 0 {
            didSet { setNeedsLayout() }
        }
    
        @IBInspectable
        open var bottomLeftRadius: CGFloat = 0 {
            didSet { setNeedsLayout() }
        }
    
        @IBInspectable
        open var bottomRightRadius: CGFloat = 0 {
            didSet { setNeedsLayout() }
        }
    
        override open func layoutSubviews() {
            super.layoutSubviews()
            applyRadiusMaskFor()
        }
    }
    

    【讨论】:

    • 我有奇怪的行为(即只有左上角被舍入),结果我正确设置了初始值,但是在动画/布局期间需要再次设置路径。因为我是从UIViewController 执行此操作的,所以我覆盖了viewDidLayoutSubviews 并再次调用它。修复了问题
    • @xaphod 有点奇怪,因为我的组件还覆盖了layoutSubviews(),它应该可以完成这项工作。可能是您的具体情况。
    • 忘了说我无法修改目标视图的类,所以我没有使用你的那部分代码。
    • 答案很好,但我正在尝试应用阴影..然后阴影不适用..
    • 记得在 didLayoutSubviews() 中设置圆角半径 - 否则你可能会遇到奇怪的行为:)
    【解决方案3】:

    是否要为每个角添加唯一角值

    之后您要添加边框吗?

    我有一个解决方案,如下所示:

    首先,添加我做的UIBezierPath扩展:

    extension UIBezierPath {
        convenience init(shouldRoundRect rect: CGRect, topLeftRadius: CGSize = .zero, topRightRadius: CGSize = .zero, bottomLeftRadius: CGSize = .zero, bottomRightRadius: CGSize = .zero){
    
            self.init()
    
            let path = CGMutablePath()
    
            let topLeft = rect.origin
            let topRight = CGPoint(x: rect.maxX, y: rect.minY)
            let bottomRight = CGPoint(x: rect.maxX, y: rect.maxY)
            let bottomLeft = CGPoint(x: rect.minX, y: rect.maxY)
    
            if topLeftRadius != .zero{
                path.move(to: CGPoint(x: topLeft.x+topLeftRadius.width, y: topLeft.y))
            } else {
                path.move(to: CGPoint(x: topLeft.x, y: topLeft.y))
            }
    
            if topRightRadius != .zero{
                path.addLine(to: CGPoint(x: topRight.x-topRightRadius.width, y: topRight.y))
                path.addCurve(to:  CGPoint(x: topRight.x, y: topRight.y+topRightRadius.height), control1: CGPoint(x: topRight.x, y: topRight.y), control2:CGPoint(x: topRight.x, y: topRight.y+topRightRadius.height))
            } else {
                 path.addLine(to: CGPoint(x: topRight.x, y: topRight.y))
            }
    
            if bottomRightRadius != .zero{
                path.addLine(to: CGPoint(x: bottomRight.x, y: bottomRight.y-bottomRightRadius.height))
                path.addCurve(to: CGPoint(x: bottomRight.x-bottomRightRadius.width, y: bottomRight.y), control1: CGPoint(x: bottomRight.x, y: bottomRight.y), control2: CGPoint(x: bottomRight.x-bottomRightRadius.width, y: bottomRight.y))
            } else {
                path.addLine(to: CGPoint(x: bottomRight.x, y: bottomRight.y))
            }
    
            if bottomLeftRadius != .zero{
                path.addLine(to: CGPoint(x: bottomLeft.x+bottomLeftRadius.width, y: bottomLeft.y))
                path.addCurve(to: CGPoint(x: bottomLeft.x, y: bottomLeft.y-bottomLeftRadius.height), control1: CGPoint(x: bottomLeft.x, y: bottomLeft.y), control2: CGPoint(x: bottomLeft.x, y: bottomLeft.y-bottomLeftRadius.height))
            } else {
                path.addLine(to: CGPoint(x: bottomLeft.x, y: bottomLeft.y))
            }
    
            if topLeftRadius != .zero{
                path.addLine(to: CGPoint(x: topLeft.x, y: topLeft.y+topLeftRadius.height))
                path.addCurve(to: CGPoint(x: topLeft.x+topLeftRadius.width, y: topLeft.y) , control1: CGPoint(x: topLeft.x, y: topLeft.y) , control2: CGPoint(x: topLeft.x+topLeftRadius.width, y: topLeft.y))
            } else {
                path.addLine(to: CGPoint(x: topLeft.x, y: topLeft.y))
            }
    
            path.closeSubpath()
            cgPath = path
        }
    }
    

    那么,添加这个UIView扩展:

    extension UIView{
        func roundCorners(topLeft: CGFloat = 0, topRight: CGFloat = 0, bottomLeft: CGFloat = 0, bottomRight: CGFloat = 0) {//(topLeft: CGFloat, topRight: CGFloat, bottomLeft: CGFloat, bottomRight: CGFloat) {
            let topLeftRadius = CGSize(width: topLeft, height: topLeft)
            let topRightRadius = CGSize(width: topRight, height: topRight)
            let bottomLeftRadius = CGSize(width: bottomLeft, height: bottomLeft)
            let bottomRightRadius = CGSize(width: bottomRight, height: bottomRight)
            let maskPath = UIBezierPath(shouldRoundRect: bounds, topLeftRadius: topLeftRadius, topRightRadius: topRightRadius, bottomLeftRadius: bottomLeftRadius, bottomRightRadius: bottomRightRadius)
            let shape = CAShapeLayer()
            shape.path = maskPath.cgPath
            layer.mask = shape
        }
    }
    

    最后,调用方法

    myView.roundCorners(topLeft: 10, topRight: 20, bottomLeft: 30, bottomRight: 40)
    

    并添加边框。显然,layer.borderRadius 不能正常工作,所以使用CAShapeLayer 和之前创建的路径创建一个边框。

    let borderLayer = CAShapeLayer()
    borderLayer.path = (myView.layer.mask! as! CAShapeLayer).path! // Reuse the Bezier path
    borderLayer.strokeColor = UIColor.red.cgColor
    borderLayer.fillColor = UIColor.clear.cgColor
    borderLayer.lineWidth = 5
    borderLayer.frame = myView.bounds
    myView.layer.addSublayer(borderLayer)
    

    瞧!

    【讨论】:

    • 我不知道为什么这个答案得分这么低。这是最好的答案。涵盖各个方面。
    • 可以简化一点,例如代替path.addLine(to: CGPoint(x: topLeft.x, y: topLeft.y)) if 可以是path.addLine(to: topLeft) 和许多类似的行。
    • 答案很好,但我正在尝试应用阴影.. 然后阴影不适用.. @ArashAfsharpour
    • @Maulikshah 在 UIView 上的阴影?还是按钮?
    【解决方案4】:

    您可以将默认的layer.cornerRadius 设置为最小值,然后将图层蒙版的边框设置为较大的值。

    let demoView = UIView(frame: CGRect(x: 100, y: 200, width: 100, height: 100))
    demoView.backgroundColor = UIColor.red
    demoView.layer.cornerRadius = 3.0
    
    let maskPath = UIBezierPath(roundedRect: demoView.bounds,
                                byRoundingCorners: [.topLeft, .topRight, .bottomLeft],
                                cornerRadii: CGSize(width: 18.0, height: 0.0))
    
    let maskLayer = CAShapeLayer()
    maskLayer.path = maskPath.cgPath
    demoView.layer.mask = maskLayer
    view.addSubview(demoView)
    

    【讨论】:

    • 按预期工作。非常感谢。
    • 它不适用于边框。反正有吗?谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-05
    • 1970-01-01
    • 2017-08-24
    相关资源
    最近更新 更多