Storyboard and autolayout: how make a circular image - ios

in storyboard (xcode 6) i want a circular user image profile take from Facebook.
So i have make this interface in storyboard, using auto layout:
Then, using Facebook iOS sdk i take the user profile (using swift):
var facebookProfileUrl = "http://graph.facebook.com/\(userId!)/picture?type=normal";
In storyboard i have set the image to "Scale to fit" mode.
To make the image view circular i use the following code:
self.facebookProfileImage.layer.cornerRadius = self.facebookProfileImage.frame.size.width / 2;
self.facebookProfileImage.clipsToBounds = true;
When i run the code, anyway the image doesn't look circular:
I suppose the problem is auto layout but i'm not sure.
How can i make the image perfectly circular??

Two steps:
Center the UIImageView by adding a "Horizontal Center In Container" constraint (Editor > Align > Horizontal Center in Container) to the UIImageView.
Remove the leading and trailing constraints you currently have set on the UIImageView.
Why? The UIImageView is getting stretched because Auto Layout needs to account for the leading and trailing constraints you set on the UIImageView. To prove my point, set the priority of the leading and trailing constraints to something less than the priority of the height and width constraints. You should see a rounded image like you expect, but it may not be centered.

More steps:
Add aspect ratio constraint 1:1
mark check clip to bounds attribute in attribute inspector
make outlet of your view into you controller class
set corner radius to half of either its height or width
yourImageViewOutlet.layer.cornerRadius = yourImageViewOutlet.frame.size.width / 2.0

I have made the same thing a little time ago and this worked for me
self.imageView.image = [ImageHelper getImage]; //retrieve image
self.imageView.layer.cornerRadius = self.imageView.frame.size.height / 2;
self.imageView.layer.masksToBounds = YES;
self.imageView.layer.borderWidth = 0;
self.imageView.contentMode = UIViewContentModeScaleAspectFill;

SWIFT 3.x
Just change your imageView custom class with this and enjoy.
#IBDesignable class RoundedImageView:UIImageView {
#IBInspectable var borderColor:UIColor = UIColor.white {
willSet {
layer.borderColor = newValue.cgColor
}
}
override func layoutSubviews() {
super.layoutSubviews()
layer.cornerRadius = frame.height/2
layer.masksToBounds = true
layer.borderWidth = 1
layer.borderColor = borderColor.cgColor
}
}

When adding the constraint, just make sure that you check the height and width so that it will be fix. At least that what I always do.

You have given leading constraint, trailing constraint and the width constraint. So the image will try to leave 130 pixels before and after the image which will increase the width of the image.
So the solution is, remove either one of the leading or trailing constraint.
The best workaround is, remove both the constraint and add a horizontal centre constraint, that is what you want.

In storyboard i have set the image to "Scale to fit" mode
But that's a problem, isn't it? It means: "Stretch the image so that it matches the way the image view is stretched." If that isn't what you want, don't say that! Use Centered, or at least use one of the content modes with "Aspect" in its name so that your image is not stretched.
As for the circle itself, setting the cornerRadius is no way to make a circle. The way to create a circular boundary around an image is to mask the image. You can redraw the image with the circular mask as a clipping boundary, or you can apply the circular mask to the image view. (See, for example, my answer here: https://stackoverflow.com/a/16475824/341994.)
It is true that your image view is also being stretched, because you gave it constraints to both sides of the superview. You can prevent that by giving it a width constraint instead; now its width will be absolute. But you should still do the right thing on the other two issues.

Related

how to remove white space in circle UIImageView?

I wanted to circle my UIImageView and added this code :
profileImage.layer.cornerRadius = profileImage.frame.size.height/2
profileImage.clipsToBounds = true
and it work perfectly, but when images are horizontal, I get this picture:
as you can see, there is white space at the bottom and top of my circle image view. but what I really wanted was a circle filled with my image!
I've tried changing "content Mode" from attribute inspector, but I didn't get any answer! how can I fix this issue?
You have already set the clipsToBound property. So just update the contentMode.
I you don't want to distort image's scale:
profileImage.contentMode = .scaleAspectFill
If image's scale does not matter, you also can use:
profileImage.contentMode = .scaleToFill
Follow the link for more details: https://useyourloaf.com/blog/stretching-redrawing-and-positioning-with-contentmode/
Use below code:-
profileImage.clipsToBounds = true
profileImage.contentMode = .scaleAspectFill
Set the contentMode of your UIImageView to scaleAspectFill
profileImage.contentMode = .scaleAspectFill
Keep in mind that using this contentMode option some portion of the content may be clipped to fill the view’s bounds.
You can set the Different Content Mode as per you choice from StoryBoard:
You can select
Scale to Fill
Aspect Fill
or any other content mode by using trial and Error method which suits you
Hope it Helps.
If I choose Aspect Fit, I'm getting blank space in top and bottom of the imageview.
Can I trim that space anyhow?
Is there any programatically constraints I can set to re-scale imageview according to actual image size?

Creating a view in IOS 10 Swift 3

Hi I want to create a view which looks something like below -
What I tried so far is I put two properties called image and text inside an UIView and tried to initialise the image view and text field and added in UIView I am able to see the image but not the text. May be I am missing proper constraints to put or something else. Can please someone help on what should be the best approach for this.
I would prefer it to be done without much involvement of storyboard i.e setting constraints for different views using storyboard. I am fine setting constraints in code. As you see it is a fairly reusable element and hence I want it as an class which can be assigned to any uiview and that should be it. Please correct me if something can be done better?
Thanks & Regards
Assumptions: the entire picture provided above is contained in a UIView and we are using Storyboard.
Refer to this picture for clarity in the explanation.
Make sure the outermost View has enough constraits so AutoLayout can properly size the view. If this doesn't happen, nothing past this point will matter.
Create 2 Views. Each has the same width as the container and is half the height. Place one in the upper half and one in the lower half. These are the ones with the blue and orange backgrounds.
Add an ImageView to the top View (blue background). Make the ImageView half the height of its Superview. Make the ImageView centered vertically in container. Add a constraint for the leading edge of the ImageView to be the same as the leading edge of the Superview margin. Add an AspectRatio constraint to the ImageView of 1:1.
Add a TextField to the top View (blue background). Center the TextField vertically in the container. Add a constraint for the HorizontalSpace between TextField leading and ImageView trailing and make the constant 8. Add a constraint for the TrailingSpace to the TextView for the SuperView trailing margin.
Change the Placeholder Text for the TextField to "Email"
Place the image in the imageview.
Repeat for the orange background View.
For the bottom borders, use this:
extension UIView{
func addBottomBorder(borderThickness: CGFloat, color: UIColor , widthPct: CGFloat) {
let border = UIView()
border.backgroundColor = color
border.autoresizingMask = [.flexibleWidth, .flexibleTopMargin]
var x: CGFloat = 0
let width = self.frame.size.width * widthPct
if widthPct < 1{
x = (self.frame.size.width - width) / 2
}
border.frame = CGRect(x: x, y: self.frame.size.height - borderThickness, width: width, height: borderThickness);
self.addSubview(border)
}
}

Aligning the bounds of a UILabel proportionally to a sister UIView in the same subview

I have a static image with an area on it that is meant to display some multi-line text. Like a speech bubble from a character in a video game. I grabbed a stock image that looks like this:
I have a UIImageView set up to be aspect-fit (see this question) inside of a subview of the main view. I have a UILabel also set up inside of the subview, which will hold the multi-line text. I want to be able to move the subview around the screen and have it be any size and still have the UIImageView stay the same aspect and have the UILabel fit inside the bubble of the image.
I made a sample project which has this set up already.
The way I intend to keep the UILabel's bounds inside the speech bubble area is by setting up constraints that are proportional to the center x and y of the UIImageView. For my image, the left edge multiplier is 0.65, the right is 1.8, the top is 0.19 and the bottom is 0.63.
I wrote a couple functions that extend from UIView to confirm this:
/**
Draws a vertical line proportional to the center x of the view.
A `proportional` value of 0 is the left edge, while 2 is the right edge.
:param: proportion The value from the left edge (0.0) to the right edge (2.0)
:param: inColor The color to draw the line in (red by default)
*/
func drawVertLineAtProportion(proportion: CGFloat, inColor: UIColor = UIColor.redColor()) {
let size = self.frame.size
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
let context = UIGraphicsGetCurrentContext()
let x = self.bounds.origin.x + proportion*self.frame.size.width/2
var vertPath = UIBezierPath()
vertPath.lineWidth = size.height/150.0
vertPath.moveToPoint(CGPointMake(x, 0))
vertPath.addLineToPoint(CGPointMake(x, self.frame.size.height))
inColor.setStroke()
vertPath.stroke()
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
self.addSubview(UIImageView(image: image))
}
And drawHorizLineAtProportion is similar, but for horizontal lines.
I can confirm that my multiplier values are correct by running these 4 lines in viewDidAppear:
imageView.drawVertLineAtProportion(0.65)
imageView.drawVertLineAtProportion(1.8)
imageView.drawHorizLineAtProportion(0.19)
imageView.drawHorizLineAtProportion(0.63)
And then the imageView looks like this:
I can change the size of the subView that contains the imageView to any size I want, and the imageView stays aspect-fit and the red box in the intersection of those red lines is always exactly what I want.
So how come when I set up the constraints of the edges of the UILabel to follow the same formula the edges don't line up?
It seems that when the width of the imageView is maxed the left and right edges are correct but the top and bottom are wrong:
And if the height is maxed, then the top and bottom are correct, but the left and right are wrong:
So how come the UILabel bounds aren't lining up with the red lines?
EDIT to specify that I know there is a runtime fix, but I want to know why storyboard doesn't work.
If I add these lines in viewDidAppear to fix the frame of the UILabel, it works:
let upperLeft: CGPoint = CGPointMake(imageView.frame.origin.x + 0.65*imageView.frame.size.width/2, imageView.frame.origin.y + 0.19*imageView.frame.size.height/2)
let lowerRight: CGPoint = CGPointMake(imageView.frame.origin.x + 1.8*imageView.frame.size.width/2, imageView.frame.origin.y + 0.63*imageView.frame.size.height/2)
let size: CGSize = CGSizeMake(lowerRight.x - upperLeft.x, lowerRight.y - upperLeft.y)
speechLabel.frame = CGRectMake(upperLeft.x, upperLeft.y, size.width, size.height)
But I still want to know why what I have set in storyboard doesn't work.
I figured out a solution, fully in storyboard, that gets me what I want, although I do believe my original question shows that there is a bug in Xcode.
I was noticing that since Xcode didn't seem to respect that I wanted to align speechLabel to the sister-UI element imageView, I just made the UIView I was aligning to no longer the imageView.
The solution I implemented was to put the imageView and speechLabel into a new parent view, which I call aspectFitView. All of the constraints that I put on the imageView to make it aspect-fit, I put on aspectFitView instead.
Then I set the constraints of imageView to make it the size of aspectFitView: align center x and y and equal width and height.
Now that the parent of speechLabel is the exact size, position, and aspect ratio of the imageView, I set up my proportional constraints for the speechLabel against the aspectFitView instead, and voila. It all works beautifully. It looks correct on my storyboard, I don't have to add any post-viewDidAppear frame-correcting code, and it works perfectly on any device I run it on.
I updated the sample project (Xcode 6.4) with the solution for anyone interested.

Circular Image distorting with Auto layout

I have my storyboard set to 4.7" while I work. When I run my app on the iP6 simulator my circular UIImageView looks nice and round. Like so:
However, I'm experiencing distortion with my circular UIImageView when I run the app in all the other simulators
Here's iP5:
and here's iP6+:
Here's the code i'm using to round the UIImageView:
profileImageView.layer.cornerRadius = profileImageView.frame.size.width / 2
profileImageView.clipsToBounds = true
The size of the UIImageView is adjusting correctly, just the roundness gets all funky as you can see. Here are the constraints I have set just in case:
1:1 ratio, align center x to view, align top to view = 15, align bottom to view = -100
The image starts as a perfect square, so I figured that with the 1:1 ratio set it would always stay circular with the code I used...what am I doing wrong here? Thanks so much!
I had this problem before and your code is 100% correct, the problem is with the autolayout and these constraints:
align top to view = 15, align bottom to view = -100
You can't align to top view and to bottom view because the screen size changes. What you can do is only align to top and find another constraint to maintain the size. What works for me with profile pictures is having a size constraint.
Before, with up and bottom constraints:
After, with up and fixed width constraints:
Where did you put that code?
The cornerRadius will not change when the view size changes. You need to update it (to match the view's size) in viewDidLayoutSubviews in your VC, or at the end of layoutSubviews in your view class.
try this definitely it will work.
swift code
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
perform(#selector(self.setCircleForImage(_:)), with: pickedImage, afterDelay: 0)
}
#objc func setCircleForImage(_ imageView : UIImageView){
imageView.layer.cornerRadius = pickedImage.frame.size.width/2
imageView.clipsToBounds = true
}
UIImage must maintain 1:1 aspect ratio

How to resize a fixed width and height UIImageView with auto layout

I have a view named myView which is always half the screen and sit at the top of screen.
Inside this view I added an UIImageView with 120x120 size which sits in center of the myView (horizontally and vertically). Inside the IB, to satisfy the constraints(X & Y) I always need to set a fixed width and height for my image, after I set center horizontally and center vertically.
But with a fixed height and width, the image doesn't resize when changing the screen size. I want my image to resize when running on iPhone5 or iPhone 4s, because myView will resize.
I need something like the image should depend on the myView size.
How to actually achieve this ?
set imageView.clipToBounds = yes, and also set imageView.contentMode = UIViewContentModeScaleAspectFit;
Update
You are talking about imageView not the image, in that case it will not resize due to constant width and height, do one thing, create IBoutLet of constraint and change there values when required, or you can also set Aspect ratio with superView
If you set the image with fixed width and height it will not change respectively.
You can either set it to be relative to myView or you can instead set leading and trailing size from all for edges and delete the center constrains.
Your constraints should look like this:
For Swift 4: Updating answer of #Adnan Aftab
imageView.clipsToBounds = true
imageView.contentMode = .scaleAspectFit

Resources