Different cornerRadius for each corner Swift 3 - iOS

后端 未结 4 1237
刺人心
刺人心 2020-12-03 16:57

I want to set different corner radius for a view in Swift -3 , I am able to set the radius for the each corner to the same value like the one mentioned in the following post

相关标签:
4条回答
  • 2020-12-03 17:33

    A slightly improved and simplified answer based on @Kirill Dobryakov's. Curves can leave very small but noticeable irregularities, when you look at it and you know it's not ideally round (try e.g. view side 40 and radius 20). I have no idea how it's even possible, but anyway, the most reliable way is to use arcs which make ideal round corners, and also an @IBDesigneable component for you:

    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()
        }
    }
    
    0 讨论(0)
  • 2020-12-03 17:36

    best way to do this after iOS 11, it looks more smooth in that way.

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

    for original answer: https://stackoverflow.com/a/50289822/4206186

    0 讨论(0)
  • 2020-12-03 17:43

    You could set the default layer.cornerRadius to the smallest value and then set the layer mask's border to the bigger value.

    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)
    
    0 讨论(0)
  • 2020-12-03 17:57

    Do you want to add unique corner value for each corner?

    Do you want to add a border after that?

    I've got a solution will look like this:

    looks like this

    First, add a UIBezierPath extension I made:

    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
        }
    }
    

    Then, add this UIView extension:

    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
        }
    }
    

    Finally, call method

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

    And add border. Apparently, layer.borderRadius won't work properly, so create a border using CAShapeLayer and previously created path.

    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)
    

    Voila!

    0 讨论(0)
提交回复
热议问题