How to Keep a Round Imageview Round Using Auto Layout

How to Set UIImageView in circle Swift 5

As @RajaKishan and @aiwiguna both said that you can't get a square image with both proportional height and width constraint together because then you can not get a round circle with different height and width.

You can set width or height proportional to superview and set the aspect ratio to 1:1 then you can change the multiplier and get the circle properly. You can check to attached image for constraints

Sample Image

then set cornerRadius in viewDidLayoutSubviews(), not in viewDidLoad(). (viewDidLoad() is called before the layout constraints change the view height, and only once. viewDidLayoutSubviews() is called any time your view's geometry changes, so you should invoke any layout logic there.

override func viewDidLayoutSubviews()  {

self.yourImageView.layer.cornerRadius = self.yourImageView.bounds.height/2
self.yourImageView.clipsToBounds = true

}

How maintain a circular uiview using auto layout without fixed height and fixed width

The first problem is that you’re pinning your view to all the edges of its parent with a fixed margin.

That may well produce a square in your storyboard, but doesn’t necessarily on your device (it depends on if your parent is constrained as a square or not, which I can’t see in your screenshots). If the parent stretches it’s width to fit it’s own superview, but doesn’t adjust its height, then your image is stretched into a rectangle.

That looks like it is the case, as the image appears stretched horizontally.

I’d suggest you remove all constraints from your image view and start again.

Make the image have a width equal to, say, 0.8 of its superview, give it a 1:1 ratio, and center it horizontally and vertically with its parent.

The second problem, is that you may be setting the cornerRadius too early.

When the view is loaded from your Storyboard, its width and height are whatever it was in storyboard.

Once the view has been laid out in its parent, the width/height will be adjusted and you’ll be left with an incorrect cornerRadius.

To solve this, simply make sure you have a 1:1 aspect ratio constraint on the view, and set the cornerRadius in viewDidLayoutSubviews (instead of viewWillLayoutSubviews).

Circular views with Autolayout (snapkit)?

I guess you want this (sorry for the plain autolayout, but I don't use snapkit):

profilePic.heightAnchor.constraint(equalTo: profilePic.widthAnchor).isActive = true
profilePic.widthAnchor.constraint(equalTo: self.view.widthAnchor, multiplier: 0.22).isActive = true

Instead of this:

make.size.equalTo(self).multipliedBy(0.22)

Make view round after autolayout

What I ended up doing was making a class called RoundView

class RoundView:UIView {
override func layoutSubviews() {
super.layoutSubviews()

self.layer.cornerRadius = self.bounds.width/2
self.layer.masksToBounds = true
}
}

And then I apply it to every view I need to be round. So in Storyboard I add RoundView to Custom Class.

What was happening was that if you look inside the source of the storyboard (XML) every view had the size of the whole screen, you can look inside your own SB code. So by trying to add a corner radius equal to the width/2 inside its parent layoutSubviews() that subview hasn't got its frame set correctly. So the corner radius got the value of 320/2 instead of 50/2, thats why it got misshaped.

UIImageView not shaping into a proper circle shape in UITableViewCell

Go to your uitableViewCell class and use below code it works for me and will work for you.

 override func awakeFromNib() {
super.awakeFromNib()
backGroundImageView.layer.cornerRadius = backGroundImageView.frame.width / 2
backGroundImageView.clipsToBounds = true
}

How to round an image automatically in Portrait and Landscape?

Try this In you ViewController

 - (void)layoutSubviews
{
[super layoutSubviews];

NSLog(@"%f", imageView.frame.size.width/2);

layer.cornerRadius = imageView.frame.size.width/2;
}

Swift - Rounded UIImageView with constraints

Put

    let dSize: CGFloat = min(imageView.frame.height, imageView.frame.width)
imageView.bounds = CGRectMake(0, 0, dSize, dSize) // centered in container you want to use bounds over frame for this scenario
imageView.layer.cornerRadius = dSize/2.0`

in viewWillLayoutSubviews

Circular (round) UIView resizing with AutoLayout... how to animate cornerRadius during the resize animation?


UPDATE: If your deployment target is iOS 11 or later:

Starting in iOS 11, UIKit will animate cornerRadius if you update it inside an animation block. Just set your view's layer.cornerRadius in a UIView animation block, or (to handle interface orientation changes), set it in layoutSubviews or viewDidLayoutSubviews.

ORIGINAL: If your deployment target is older than iOS 11:

So you want this:

smoothly resizing circle view

(I turned on Debug > Slow Animations to make the smoothness easier to see.)

Side rant, feel free to skip this paragraph: This turns out to be a lot harder than it should be, because the iOS SDK doesn't make the parameters (duration, timing curve) of the autorotation animation available in a convenient way. You can (I think) get at them by overriding -viewWillTransitionToSize:withTransitionCoordinator: on your view controller to call -animateAlongsideTransition:completion: on the transition coordinator, and in the callback you pass, get the transitionDuration and completionCurve from the UIViewControllerTransitionCoordinatorContext. And then you need to pass that information down to your CircleView, which has to save it (because it hasn't been resized yet!) and later when it receives layoutSubviews, it can use it to create a CABasicAnimation for cornerRadius with those saved animation parameters. And don't accidentally create an animation when it's not an animated resize… End of side rant.

Wow, that sounds like a ton of work, and you have to involve the view controller. Here's another approach that's entirely implemented inside CircleView. It works now (in iOS 9) but I can't guarantee it'll always work in the future, because it makes two assumptions that could theoretically be wrong in the future.

Here's the approach: override -actionForLayer:forKey: in CircleView to return an action that, when run, installs an animation for cornerRadius.

These are the two assumptions:

  • bounds.origin and bounds.size get separate animations. (This is true now but presumably a future iOS could use a single animation for bounds. It would be easy enough to check for a bounds animation if no bounds.size animation were found.)
  • The bounds.size animation is added to the layer before Core Animation asks for the cornerRadius action.

Given these assumptions, when Core Animation asks for the cornerRadius action, we can get the bounds.size animation from the layer, copy it, and modify the copy to animate cornerRadius instead. The copy has the same animation parameters as the original (unless we modify them), so it has the correct duration and timing curve.

Here's the start of CircleView:

class CircleView: UIView {

override func layoutSubviews() {
super.layoutSubviews()
updateCornerRadius()
}

private func updateCornerRadius() {
layer.cornerRadius = min(bounds.width, bounds.height) / 2
}

Note that the view's bounds are set before the view receives layoutSubviews, and therefore before we update cornerRadius. This is why the bounds.size animation is installed before the cornerRadius animation is requested. Each property's animations are installed inside the property's setter.

When we set cornerRadius, Core Animation asks us for a CAAction to run for it:

    override func action(for layer: CALayer, forKey event: String) -> CAAction? {
if event == "cornerRadius" {
if let boundsAnimation = layer.animation(forKey: "bounds.size") as? CABasicAnimation {
let animation = boundsAnimation.copy() as! CABasicAnimation
animation.keyPath = "cornerRadius"
let action = Action()
action.pendingAnimation = animation
action.priorCornerRadius = layer.cornerRadius
return action
}
}
return super.action(for: layer, forKey: event)
}

In the code above, if we're asked for an action for cornerRadius, we look for a CABasicAnimation on bounds.size. If we find one, we copy it, change the key path to cornerRadius, and save it away in a custom CAAction (of class Action, which I will show below). We also save the current value of the cornerRadius property, because Core Animation calls actionForLayer:forKey: before updating the property.

After actionForLayer:forKey: returns, Core Animation updates the cornerRadius property of the layer. Then it runs the action by sending it runActionForKey:object:arguments:. The job of the action is to install whatever animations are appropriate. Here's the custom subclass of CAAction, which I've nested inside CircleView:

    private class Action: NSObject, CAAction {
var pendingAnimation: CABasicAnimation?
var priorCornerRadius: CGFloat = 0
public func run(forKey event: String, object anObject: Any, arguments dict: [AnyHashable : Any]?) {
if let layer = anObject as? CALayer, let pendingAnimation = pendingAnimation {
if pendingAnimation.isAdditive {
pendingAnimation.fromValue = priorCornerRadius - layer.cornerRadius
pendingAnimation.toValue = 0
} else {
pendingAnimation.fromValue = priorCornerRadius
pendingAnimation.toValue = layer.cornerRadius
}
layer.add(pendingAnimation, forKey: "cornerRadius")
}
}
}
} // end of CircleView

The runActionForKey:object:arguments: method sets the fromValue and toValue properties of the animation and then adds the animation to the layer. There's a complication: UIKit uses “additive” animations, because they work better if you start another animation on a property while an earlier animation is still running. So our action checks for that.

If the animation is additive, it sets fromValue to the difference between the old and new corner radii, and sets toValue to zero. Since the layer's cornerRadius property has already been updated by the time the animation is running, adding that fromValue at the start of the animation makes it look like the old corner radius, and adding the toValue of zero at the end of the animation makes it look like the new corner radius.

If the animation is not additive (which doesn't happen if UIKit created the animation, as far as I know), then it just sets the fromValue and toValue in the obvious way.

Here's the whole file for your convenience:

import UIKit

class CircleView: UIView {

override func layoutSubviews() {
super.layoutSubviews()
updateCornerRadius()
}

private func updateCornerRadius() {
layer.cornerRadius = min(bounds.width, bounds.height) / 2
}

override func action(for layer: CALayer, forKey event: String) -> CAAction? {
if event == "cornerRadius" {
if let boundsAnimation = layer.animation(forKey: "bounds.size") as? CABasicAnimation {
let animation = boundsAnimation.copy() as! CABasicAnimation
animation.keyPath = "cornerRadius"
let action = Action()
action.pendingAnimation = animation
action.priorCornerRadius = layer.cornerRadius
return action
}
}
return super.action(for: layer, forKey: event)
}

private class Action: NSObject, CAAction {
var pendingAnimation: CABasicAnimation?
var priorCornerRadius: CGFloat = 0
public func run(forKey event: String, object anObject: Any, arguments dict: [AnyHashable : Any]?) {
if let layer = anObject as? CALayer, let pendingAnimation = pendingAnimation {
if pendingAnimation.isAdditive {
pendingAnimation.fromValue = priorCornerRadius - layer.cornerRadius
pendingAnimation.toValue = 0
} else {
pendingAnimation.fromValue = priorCornerRadius
pendingAnimation.toValue = layer.cornerRadius
}
layer.add(pendingAnimation, forKey: "cornerRadius")
}
}
}
} // end of CircleView

My answer was inspired by this answer by Simon.



Related Topics



Leave a reply



Submit