David Mempin
David Mempin

Reputation: 55

UIView diagonal border on one corner

I have a view that needs to be displayed with a slanted corner on one side. I've already done it when the view has a background color like this:

enter image description here

But I also need it to be displayed with a clear background. After setting its background to clear and adding a border to it this is the output:

enter image description here

Here is the code for the custom view that I'm using to create the diagonal corner:

class PointedView: UIImageView {
    @IBInspectable var borderColor: UIColor = UIColor.clear {
        didSet {
            layer.borderColor = borderColor.cgColor
        }
    }
    
    @IBInspectable var borderWidth: CGFloat = 0 {
        didSet {
            layer.borderWidth = borderWidth
        }
    }
    
    @IBInspectable
    /// Percentage of the slant based on the width
    var slopeFactor: CGFloat = 15 {
        didSet {
            updatePath()
        }
    }
    
    private let shapeLayer: CAShapeLayer = {
        let shapeLayer = CAShapeLayer()
        shapeLayer.lineWidth = 0
        
        // with masks, the color of the shape layer doesn’t matter;
        // it only uses the alpha channel; the color of the view is
        // dictate by its background color
        shapeLayer.fillColor = UIColor.white.cgColor
        return shapeLayer
    }()
    
    override func layoutSubviews() {
        super.layoutSubviews()
        updatePath()
    }
    
    private func updatePath() {
        let path = UIBezierPath()
        
        // Start from x = 0 but the mid point of y of the view
        path.move(to: CGPoint(x: 0, y: bounds.midY*2))
        
        // Create the top slanting line
        path.addLine(to: CGPoint(x: bounds.minX, y: bounds.minY))
        
        // Straight line from end of slant to the end of the view
        path.addLine(to: CGPoint(x: bounds.maxX, y: bounds.minY))
        
        // Straight line to come down to the bottom, perpendicular to view
        path.addLine(to: CGPoint(x: bounds.maxX, y: ((bounds.maxY*3)/4) + 20))
        
        // Go back to the slant end position but from the bottom
        path.addLine(to: CGPoint(x: (bounds.maxX*3)/4, y: bounds.maxY))
        
        // Close path back to where you started
        path.close()
        
        shapeLayer.path = path.cgPath
        layer.mask = shapeLayer
    }
}

Is there any possible solution to this?

Upvotes: 0

Views: 149

Answers (4)

Muhammad Manzar
Muhammad Manzar

Reputation: 29

Please use this method

func roundCorners(corners: UIRectCorner = .allCorners, radius: CGFloat = 0.0, borderColor: UIColor = .clear, borderWidth: CGFloat = 0.0, clipToBonds: Bool = true) {
    clipsToBounds = clipToBonds
    layer.cornerRadius = radius
    layer.borderWidth = borderWidth
    layer.borderColor = borderColor.cgColor
    
    if corners.contains(.allCorners){
        layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner, .layerMinXMaxYCorner, .layerMaxXMaxYCorner]
        return
    }
    
    var maskedCorners = CACornerMask()
    if corners.contains(.topLeft) { maskedCorners.insert(.layerMinXMinYCorner) }
    if corners.contains(.topRight) { maskedCorners.insert(.layerMaxXMinYCorner) }
    if corners.contains(.bottomLeft) { maskedCorners.insert(.layerMinXMaxYCorner) }
    if corners.contains(.bottomRight) { maskedCorners.insert(.layerMaxXMaxYCorner) }
    layer.maskedCorners = maskedCorners
}

and by using your UIVIEW

View.roundCorners(corners: [.topLeft, .bottomLeft], radius: 20, borderColor: .clear, borderWidth: 0, clipToBonds: true)

Upvotes: 0

Jaykant
Jaykant

Reputation: 399

class PointedView: UIView {

override init(frame: CGRect) {
    super.init(frame: frame)
    setup()
}
required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    setup()
}
func setup() {
    let shapeLayer = CAShapeLayer()
    shapeLayer.path = createBezierPath().cgPath
    shapeLayer.strokeColor = UIColor.blue.cgColor
    shapeLayer.fillColor = UIColor.blue.cgColor
    shapeLayer.lineWidth = 1.0
    shapeLayer.position = CGPoint(x: 10, y: 10)
    self.layer.addSublayer(shapeLayer)
}

func createBezierPath() -> UIBezierPath {
    let path = UIBezierPath()
    
    // Start from x = 0 but the mid point of y of the view
    path.move(to: CGPoint(x: 0, y: bounds.midY*2))
    
    // Create the top slanting line
    path.addLine(to: CGPoint(x: bounds.minX, y: bounds.minY))
    
    // Straight line from end of slant to the end of the view
    path.addLine(to: CGPoint(x: bounds.maxX, y: bounds.minY))
    
    // Straight line to come down to the bottom, perpendicular to view
    path.addLine(to: CGPoint(x: bounds.maxX, y: ((bounds.maxY*3)/4) + 20))
    
    // Go back to the slant end position but from the bottom
    path.addLine(to: CGPoint(x: (bounds.maxX*3)/4, y: bounds.maxY))
    
    // Close path back to where you started
    path.close() // draws the final line to close the path
    return path
}
}

Upvotes: 1

Muhammad Manzar
Muhammad Manzar

Reputation: 29

if you are using StoryBoard with @IBInspectable you can try like thisenter image description here

Upvotes: -1

David Mempin
David Mempin

Reputation: 55

Managed to solve it by drawing another CAShapeLayer() following the same path as the original shape.

let borderLayer = CAShapeLayer()
borderLayer.path = path.cgPath
borderLayer.lineWidth = 2
borderLayer.strokeColor = borderColor.cgColor
borderLayer.fillColor = UIColor.clear.cgColor
borderLayer.frame = bounds
    
layer.addSublayer(borderLayer)

enter image description here

Upvotes: 0

Related Questions