Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
154 views
in Technique[技术] by (71.8m points)

ios - circle collectionview image according to device size

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

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

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...