I’ a little confused with UIView’s bounds and frame. I’m creating UIButton manually with the same size as its super view:
UIButton *button = [[UIButton alloc]initWithFrame:aView.bounds];
button.backgroundColor = [UIColor blueColor];
[aView addSubview:button];
But in the simulator the button and its super view have different size. I don’t really understand this..
(I didn't use IB to create the button because next I’d like to create a 2D array of buttons within that super view, so I think maybe it’s better to create them manually)
I strongly suspect you're putting you code in viewDidLoad before the view has has a chance to finish laying out its subviews. Move your code to viewDidLayoutSubviews instead.
You are correct to use aView.frame rather than aView.bounds. Both will give you the size (width and height of the aView) but frame gives you the position of aView in its superview. The button will need the position relative to aView not aView's superview. Bounds will give you aView's position in its own coordinate system (most likely 0, 0).
What could be happening is you are creating the button using aViews size before aView's frame has been determined. When is aView's frame being determined? Is aView being created via interface builder? When are you creating the button?
The code you provided does work - that is the correct way to make a subview the same size as its superview. There are two possible explanations for why you think that isn't happening:
You might be misinterpreting what you see in the simulator. The view you see behind the button might not be aView. I'm going to discount that possibility and go with the second possibility:
You are running that code before aView achieves its final size. In other words, you are inserting button, but then layout comes along and changes the size of aView. That change in the size of aView doesn't change the size of button, so button is left with the size aView used to have at the time you created and inserted it.
Related
I am very new to iOS development and have never done auto layout before ,I have actually seven buttons on a view controller that needs to look round on every screen without fixing height and width....I have looked many tutorials but couldn't understand that how I can add constraints on those round buttons and show them at same position on every screen. I want the buttons to actually increase size when screen increase and decrease when screen size decreases.Please help and show which constraints should be added.!this shows how buttons are added on my view controller
If you want perfect round buttons(circle) then width and height should be same. For that set the aspect constraint with multipler 1:1 so that width and height will become equal.
Based on the the screenshot you have provided, see below how the constraints should look like:
Well, two points:
Position: Well, you need understand accurately ‘same position in every screen’, I guess you know view.frame = CGRectMake(10, 20, 50, 50)but same code not lead to 'same position' in different screen, important thing is which way you want. Think about a increasing screen, you have a square on it, what do you want this square change? Different change style lead to different code.
Size: You said you want square increasing or decreasing with screen, the basic way is let square.width && square.height changing with screen, if use frame layout you may write view.frame = CGRectMake(10, 20, SCWidth * 0.0666, SCHeight * 0.0833), certainly autoLayout support scale calculate, I recommend you use Masonry to add layout, sample code like:
[square mas_remakeConstraints:^(MASConstraintMaker *make) {
make.width.equalTo(self.mas_width).multipliedBy(0.0083);
}];
of course if you use xib to do it, you can see constraints have multiplier property to fix problem.
Use this code to make round button..
You can programmatically get the current height of Button and then assign the half of height to corner radius to make it round.
[self.view layoutIfNeeded];
[self.view setNeedsLayout];
self.yourButton.layer.cornerRadius = self.yourButton.frame.size.height/2;
self.yourButton.clipsToBound = YES;
I'm trying to adjust the size of a button to (it's intrinsic size + a little bit more) in order to draw a custom background. However, every time I access self.titleLabel within the button, the size and position resnaps to that of the storyboard. I don't have to do anything with the label to reproduce this, just retrieve it from the button.
I've put logging code all over my button and view controller in order to find where this is happening. It's not coming from a relaying-out of subviews or any other notification I see to get within the view controller. The line before accessing titleLabel, the position and size are correct. The line after, it has snapped back to the storyboard position. Commenting out the access prevents the size/position snapping. Can someone tell me where or why this is happening?
I have no constraints set (that I can tell), but am I fighting against auto-layout here? Should I be doing this a different way like composing controls or something?
Something similar (or the same?) has been asked before at UIButton modifying titlelabel seems to change its frame and UIButton titleLabel resizes on press?, but both were left unanswered or explained away with just "maybe a bug."
If the project has auto-layout enabled, then YES, you're fighting auto-layout. You have two choices, either subclass UIButton so that you can override the intrinsic size calculation, or modify the constraints so that the intrinsic size is not used in any constraint. If you do the latter, then you probably want to create an IBOutlet to the constraint for the width, so that you can adjust the constant property as needed.
This isn't a bug, it's a consequence of auto layout. When using auto layout, you shouldn't set any frames. Instead, you should change the size or position by modifying the constraints. What's happening, is that whenever the view needs to be redrawn, the frame reverts to the frame that's defined by the constraints.
My app has a UIView called stepView that needs to grow and shrink, always expanding down and to the right, and always shrinking up and to the left. It has a subview, durationLabel, which runs along the entire width of the stepView and has a fixed height.
When the stepView is animated to grow larger, the label grows properly along with it: the text and the label's background slide to the right in sync with the growing stepView. However, when the stepView is animated to grow smaller, it immediately snaps to its new size, leaving a gap between the stepView's shrinking right edge and its right edge until the animation completes.
The label initialization code in stepView.m:
CGRect duration_frame = CGRectMake(0, 0, self.frame.size.width, HEADER_HEIGHT);
self.durationLabel = [[UILabel alloc] initWithFrame:duration_frame];
[self.durationLabel setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
[self addSubview:self.durationLabel];
And the animation code:
[UIView animateWithDuration:ANIM_DURATION
animations:^{
[stepView setFrame:newFrame];
}
];
Using bounds/center instead of frame produces the same effect. I've considered using a transform instead, but the code for calculating "newFrame" is somewhat involved, so I'd rather avoid rewriting it if possible. I've also tried manually changing the label's frame in the same animation block, but that simply makes it disappear entirely (possibly because I was trying to animate both a view's frame and its subview's frame in the same animation block?). I've also confirmed stepView and its subviews aren't undergoing any other animations at the same time, although there are animations happening to unrelated views in separate animation blocks.
I'm at a loss for why the label should animate perfectly when the stepView grows but fail to animate at all when it shrinks. I haven't seen anything in the documentation that indicates there would be a difference. Thank you for any help you can provide.
I think this is an issue with UILabel - using another UIView as subview instead of an UILabel the animation works fine also when you shrink.
If I understand correctly what you need to obtain as result, however, I would suggest you to try the following:
don't set the autoresizingMask property
// [self.durationLabel setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
set the stepView clipToBounds property to YES
self.clipToBounds = YES;
This way the UILabel frame will not change but only the part which is actually within the stepView bounds will be visible. I hope this might help.
Update: just done a quick research and found that the question is already answered here resize uiview with UILabel and animate it correctly - the answers provided seem to be aligned to what I've suggested above.
I am using Auto layout and it's driving me crazy. I have done everything I could to prevent UIImageView from stretching all over. I have no idea why it does that. I tried using constraints, solving auto layout issues. For now, the only solution was turning the auto layout itself.
Could anyone please tell me why xcode is completely ignoring my constraints? I would expect the UIImage to stay as 320x320 when I explicitly set it as that, but noooooooo....
I want to post images, but the site won't let me, and I would like to add code to this question so that it is more specific, but there's literally no code at all. I just dragged "UIImageView" from storyboard, made it small, set constraints as is, and it's just ignoring my code.
You'll want to make sure your UIImageView is set to clip to bounds. If not, the image will spill out of the view and will appear to not stretch correctly (even though in reality it is).
In interface builder, make sure the Clip Subviews box is checked.
If you're not using interface builder, the following code will do the same thing:
yourImageView.clipsToBounds = YES;
With autolayout, the values in the Size Inspector are pretty much ignored.
You might expect that if a number is typed into the boxes on the Size Inspector, Xcode would automatically create constraints to reflect what you typed, but it doesn't. You need to create "Pin" constraints on your own for the height and width of your UIImageView.
Select the image view on your storyboard
Click the "Pin" button at the bottom-right of the storyboard screen
Type the desired size into the "Width" and "Height" fields, and make sure the boxes are checked
Click the "Add 2 constraints" button
When you are done, you should be able to see your constraints in the Size Inspector on the right side of the screen (the purple boxes)
My problem was with the ContentHuggingPriority and ContentCompressionResistancePriority.
The first controls how important it is to keep the view "hugging" the image (staying close to it and not expanding) and the latter controls how resistant to compression the view is.
We use PureLayout, so the code to fix it was:
[NSLayoutConstraint autoSetPriority:ALLayoutPriorityRequired forConstraints:^{
[myImageView autoSetContentCompressionResistancePriorityForAxis:ALAxisHorizontal];
[myImageView autoSetContentHuggingPriorityForAxis:ALAxisHorizontal];
}];
(my problem was only in the horizontal axis)
May 15, 2016: Updated to PureLayout v3 syntax. If you use a version <= 2 just put UIView instead of NSLayoutConstraint. Thanks Rudolf J!
I had the same problem. I added a UIImageView into a prototype cell and wanted to align it next to the text but it kept stretching the image when I applied the constraints. In my case, I changed the 'Mode' property for the Image View to 'Aspect Fit' and it worked fine.
You can try to add UIImageView programmatically.
Call this code in your viewDidLoad method or where you want.
UIImageView *yourImageView = [[UIImageView alloc]initWithFrame:CGRectMake(50.0f, 50.0f, 320.0f, 320.0f)]; // x and y coordinates, width and height of UIImageView
[yourImageView setImage:[UIImage imageNamed:#"your_image.png"]];
[yourImageView setContentMode:UIViewContentModeCenter]; // you can try use another UIViewContentMode
[self.view addSubview:yourImageView];
my UIView has a dynamic amount of views inside of it and also has a background color to it. I'm trying to tuck the UIView in around all the items, but it's not working.
[self sizeToFit] Seems to work just fine on a UILabel, but not on a UIView.
I know I can calculate the area manually by looping through all the subviews, but that just seems like too much work for something like this.
I'm hoping someone knows a simpler way.. Thanks
UPDATE
If you're using auto layout, you can make your container view fit its subviews snugly. Set up constraints between your container and its subviews, and set up constraints between the subviews and the container's superview, but do not set up constraints between the container and its superview.
ORIGINAL
There's no built-in support for automatically shrink-wrapping a view around its subviews.
The sizeToFit method works by sending [self sizeThatFits:self.bounds.size], then resizing itself based on the size returned by sizeThatFits:.
UILabel overrides the sizeThatFits: method to compute the size of its text in its font.
You will need make a custom UIView subclass and override sizeThatFits:. It's pretty simple:
- (CGSize)sizeThatFits:(CGSize)size {
CGRect rect = CGRectZero;
for (UIView *subview in self.subviews)
rect = CGRectUnion(rect, subview.frame);
return rect.size;
}
I don't think there is a "dynamic" way. You see, resizing only works the way around, a subview ca be made to dynamicaly change it's size when a superview does.
Anyway, what you are describing as "too much work" is exactly (more or less) what sizeToFit does...