How to add a border to a circular image with mask

前端 未结 2 930
别跟我提以往
别跟我提以往 2021-01-14 06:54

This is my attempt:

func round() {
    let width = bounds.width < bounds.height ? bounds.width : bounds.height
    let mask = CAShapeLayer()
    mask.path         


        
2条回答
  •  被撕碎了的回忆
    2021-01-14 07:06

    If you have subclassed UIImageView, for example, you can override layoutSubviews such that it (a) updates the mask; (b) removes any old border; and (c) adds a new border. In Swift 3:

    import UIKit
    
    @IBDesignable
    class RoundedImageView: UIImageView {
    
        /// saved rendition of border layer
    
        private weak var borderLayer: CAShapeLayer?
    
        override func layoutSubviews() {
            super.layoutSubviews()
    
            // create path
    
            let width = min(bounds.width, bounds.height)
            let path = UIBezierPath(arcCenter: CGPoint(x: bounds.midX, y: bounds.midY), radius: width / 2, startAngle: 0, endAngle: .pi * 2, clockwise: true)
    
            // update mask and save for future reference
    
            let mask = CAShapeLayer()
            mask.path = path.cgPath
            layer.mask = mask
    
            // create border layer
    
            let frameLayer = CAShapeLayer()
            frameLayer.path = path.cgPath
            frameLayer.lineWidth = 32.0
            frameLayer.strokeColor = UIColor.white.cgColor
            frameLayer.fillColor = nil
    
            // if we had previous border remove it, add new one, and save reference to new one
    
            borderLayer?.removeFromSuperlayer()
            layer.addSublayer(frameLayer)
            borderLayer = frameLayer
        }
    }
    

    That way, it responds to changing of the layout, but it makes sure to clean up any old borders.

    By the way, if you are not subclassing UIImageView, but rather are putting this logic inside the view controller, you would override viewWillLayoutSubviews instead of layoutSubviews of UIView. But the basic idea would be the same.

    --

    By the way, I use a mask in conjunction with this shape layer because if you merely apply rounded corners of a UIView, it can result in weird artifacts (look at very thin gray line at lower part of the circular border):

    If you use the bezier path approach, no such artifacts result:

    For Swift 2.3 example, see earlier revision of this answer.

提交回复
热议问题