Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

Hello in my horizontal collectionview i want to circle image , if i set static height and width it works but it does not work if i set constraint iam using this method to circle my image

    public static func circularImageWhite(photoImageView: UIImageView?)
{
    photoImageView!.layer.frame = photoImageView!.layer.frame.insetBy(dx: 0, dy: 0)
    photoImageView!.layer.borderColor = UIColor.white.cgColor
    photoImageView!.layer.cornerRadius = photoImageView!.frame.height/2
    photoImageView!.layer.masksToBounds = false
    photoImageView!.clipsToBounds = true
    photoImageView!.layer.borderWidth = 1
    photoImageView!.contentMode = UIViewContentMode.scaleAspectFill
}

i want to circle image on every device

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
152 views
Welcome To Ask or Share your Answers For Others

1 Answer

Everything about your code is wrong.

photoImageView!.layer.frame = photoImageView!.layer.frame.insetBy(dx: 0, dy: 0)

That line is meaningless. If you inset the frame by zero you are not changing it. So that line does nothing at all.

photoImageView!.layer.masksToBounds = false
photoImageView!.clipsToBounds = true

A layer's masksToBounds and a view's clipsToBounds are actually the very same property. So you are setting the same property to false and then back to true in the very next line. Thus the first of those two lines does nothing at all.

photoImageView!.layer.cornerRadius = photoImageView!.frame.height/2

That is actually the heart of the matter. The problem is that you are setting the corner radius according to the frame height. But that assumes you know what the frame is. You don't. As you yourself said, this doesn't work if you set autolayout constraints on your view. Why? Because of the order in which things happen:

  1. First, you use the current frame height to set the corner radius.

  2. Then, the constraints kick in and change the frame. So now the corner radius that you set before doesn't "fit" the image view any more.

Moreover, setting the corner radius is a lousy way to clip a view to a circle. The correct way is to mask the view to an actual circle.

So, to sum up: You should use a UIImageView subclass that overrides its own layoutSubviews to set its own mask to a circle that fits the current size. As the size changes due to constraints, layoutSubviews will be called and your code will change the mask to fit properly.

(The white circular border can be yet another layer or subview that draws the circle.)

The matter comes up quite often, and I often see the cornerRadius misused in this same way, so here's an actual implementation:

class CircleImageView : UIImageView {
     override func layoutSubviews() {
        super.layoutSubviews()
        self.layer.sublayers = nil
        let radius = min(self.bounds.height, self.bounds.width)/2
        let cen = CGPoint(x:self.bounds.width/2, y:self.bounds.height/2)
        let r = UIGraphicsImageRenderer(size:self.bounds.size)
        var im : UIImage?
        var outline : UIImage?
        r.image { ctx in
            let con = ctx.cgContext
            UIColor.black.setFill()
            con.addArc(center: cen, radius: radius, 
                startAngle: 0, endAngle: .pi*2, clockwise: true)
            let p = con.path
            con.fillPath()
            im = ctx.currentImage
            con.clear(CGRect(origin:.zero, size:self.bounds.size))
            con.addPath(p!)
            UIColor.clear.setFill()
            UIColor.white.setStroke() // border color, change as desired
            con.setLineWidth(4) // border width, change as desired
            con.strokePath()
            outline = ctx.currentImage
        }
        // the circle mask
        let iv = UIImageView(image:im)
        iv.contentMode = .center
        iv.frame = self.bounds
        self.mask = iv
        // the border
        let iv2 = UIImageView(image:outline)
        iv2.contentMode = .center
        iv2.frame = self.bounds
        self.addSubview(iv2)
    }
}

Result:

enter image description here

Use CircleImageView as your image view and you'll get the right result. I repeat: the important thing is that this will continue to work no matter how the CircleImageView itself is subsequently resized.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...