circle collectionview image according to device si

2019-08-20 08:54发布

问题:

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

回答1:

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:

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.