UIView Autoresizing Resources - iphone

I've been working on autoresizing a custom UIView and Apple has very little to say on this. What's more, based on SO feedback, Apple's documentation is actually wrong in some areas. Finally, even though there are six resizing components in Interface Builder and six for setAutoresizingMask: they don't seem to correlate at all. For example, setting the width spring in IB has a different effect from setting the autoresizingMask to UIViewAutoresizingFlexibleWidth when rotating the device.
Are there any good resources for learning about how resizing works on the iPhone?
Edit:
I understand the basic concepts Apple uses such as contentMode, and I've read through the UIView documentation. I'm looking for something that explains a little more deeply what the IB settings do in terms of what's available in the SDK programmatically.

setting the autoresizingMask to UIViewAutoresizingFlexibleWidth, is equivalent to setting the width spring, plus both the left and right struts in Interface Builder (the struts mean that the edge is not flexible). If you wanted to replicate the behavior of only setting the width spring, but not the left and right struts, you would have to set autoresizingMask to UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin

I found this post helpful in understanding iOS autoresizing.
http://www.techotopia.com/index.php/IOS_4_iPhone_Rotation,_View_Resizing_and_Layout_Handling

From Apple:
... specify the value of this mask by combining the constants described in
UIViewAutoresizing using the C bitwise OR operator. Combining these
constants lets you specify which dimensions of the view should grow or
shrink relative to the superview. The default value of this property
is UIViewAutoresizingNone, which indicates that the view should not be
resized at all.
... For example,
suppose this property includes the UIViewAutoresizingFlexibleWidth and
UIViewAutoresizingFlexibleRightMargin constants but does not include
the UIViewAutoresizingFlexibleLeftMargin constant, thus indicating
that the width of the view’s left margin is fixed but that the view’s
width and right margin may change. Thus, the view appears anchored to
the left side of its superview while both the view width and the gap
to the right of the view increase.
If the autoresizing behaviors do not offer the precise layout that you
need for your views, you can use a custom container view and override
its layoutSubviews method to position your subviews more precisely.
So if you would like to position a view anchored to the top and right side of its superview, you might apply a mask like:
[myView setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin];

superview has such parameters as contentMode and autoresizesSubviews, wich all with autoresizingMask of its subviews makes resizing behavior
read attentively http://developer.apple.com/library/ios/#documentation/uikit/reference/UIView_Class/UIView/UIView.html

For the record, I scratched my head for an hour because my one-line UILabel just would NOT auto-adjust font size to fit width. Finally, this did the trick:
label.contentMode = UIViewContentModeScaleAspectFit;
I googled and no one seems to clarify this detail (everyone tells you the label should be 1 line, set adjustsFontSizeToFitWidth/minimumFontSize etc.).
Perhaps this property's default value changed? I'm on iOS 4.3.

Related

iOS: how to adjust positions of UI elements one by one properly by IB when some of them may change size?

For example, on a UIView, from left to right there are three buttons:,button1,button2,button3.
When button 1 become wider, such as its width become twice as its original width, is there any interface builder way that can make button2&3 move right automatically?
sorry for I didn't make my question clear.
I mean such kind of size change: I push button1, then I change it's frame in my code, not caused by the change of text in butotn1. I want button2&3 to move right automatically, keeping the width of the gap between button 1 and 2 unchanged.
Thanks everyone.
IB can be used only for initional positioning of views.
True, you can also define autoresizing masks of the views but that's about it.
Any additional laying out should be done in code.
I could be wrong, but I don't know of any way you can do this in IB. It's pretty straight forward in code though, just link the buttons to some IBOutlets and check the sizes of the images of the buttons (myUIImage.size), then adjust the frames of the buttons (do it in viewWillAppear).
Seen your edit - if you're adjusting its size using code, adjust its position too.
If your buttons are in a row at the bottom of the screen, consider using a UIToolBar. Its UIBarButtonItem objects automatically adjust to fit each other's width changes. For more generic cases, you'll need to recalculate positions and sizes as in Franklyn Weber's answer.
Yes - by using autoresizing masks. If you allow the margins to be flexible (no red lines connecting the frame to the superview's frame) and allow flexible width and height, the buttons will size and move proportionally.

How to anchor UIView a few pixel off the middle point using Autoresizing Mask?

Observe the following screenshot:
How do I anchor UIView a few pixel off the middle point using Autoresizing Mask so that it is always 20px to the left of the middle point?
I have tried setting the autoresizingMask property to UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin and it's not really doing it.
I did manage to do it if I wrap the view in another bigger view that fills the entire screen and doesn't resize at all. But is there a way to do it without an additional view?
Autoresizing masks don't handle this case very well, as you've already discovered. They work great if you want to keep something a fixed distance from its superview or proportionally resizing/repositioning somewhere in the middle. You can do a surprising amount with just those options, but off-center anchoring is not something you can do easily
If you want do this with autoresizing masks, you'll need to put your box inside another empty UIView, one that is in a more convenient position for autoresizing masks. It will look like this.
Here's what you've got right now:
center
|
|---------------------------------------------------| <-- The main parent view
|-----| <-- your view
What you want is this:
center
|
|---------------------------------------------------| <-- The main parent view
|--------------------| <-- The new view, centered in the parent
|-----| <-- your view
The new view should be completely transparent, have a fixed width, and a flexible distance from both sides of the parent view. It should be wide enough to fully contain the off-center box, and no wider. If it is positioned exactly in the center of the main parent view, it will stay centered no matter what happens to the size of the parent view.
Then add your box as a subview of the new view, with a fixed width and fixed distance from the left edge of the parent. Now, using only autoresizing masks, your view will stay where you want it.
A simpler option might be to override -layoutSubviews on your view, or -viewDidLayoutSubviews on your controller (available iOS 5.0 and later) and just manually position the view. But you asked how to do it with autoresizing masks, so that's what you got. Without adding an extra view, there's no way to use autoresizing masks to get the positioning behavior you want.
I guess the best solution is to set center property to:
myview.center = CGPointMake(self.view.frame.size.width/2-20, myview.center.y);
And set up it in willRotate method.
Not exactly an answer, more of an avenue for exploration. You can try playing with the layer-level property anchorPoint. Setting it to (1.0, 0.5) means the layer's position will be defined by its right edge. In that case centered would mean the right edge is centered. Set flexible left margin and flexible right margin and it might stay left of the center.
To get it exactly 20p left of the center, just set the anchorPoint to 20p right of the center of the view. (But anchorPoint units are a fraction of the size of the layer, so do some math to find the right value.)
I'm not sure if it will work. I'm not sure what the effects are of mixing layer-level positioning with autoresizing.

Rotating the uiview without IB

In my app all my controls are created in code. I have not used IB for controls. now i want to rotate the view to landscape mode. I know I have to use the shouldAutorotate method for this purpose.
But since I have not used IB, how can I resize the controls when they are in landscape mode? How can I position them correctly using code only?
In most cases you can get views to resize themselves appropriately just by setting their autoresizingMask property to some combination of:
UIViewAutoresizingFlexibleLeftMargin
UIViewAutoresizingFlexibleRightMargin
UIViewAutoresizingFlexibleTopMargin
UIViewAutoresizingFlexibleBottomMargin
UIViewAutoresizingFlexibleWidth
UIViewAutoresizingFlexibleHeight
For example, let's say you want a view's width to increase when you rotate it to landscape, you want it to maintain the same margins relative to the top, left, and right sides of the screen, and you want its height to remain the same. This means that out of the six attributes above, only the width and bottom margin should be flexible. The other four attributes are fixed. So you would do:
yourView.autoresizingMask = UIViewAutoResizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin;
In those rare cases when you can't get the views to behave appropriately using their autoresizingMask property, you can wrap them in a custom view and override that view's layoutSubviews method. This method gets called when the view's frame changes due to autorotation, so you can check [[UIApplication sharedApplication] statusBarOrientation] and update the frames of your subviews manually.
You position them correctly using code the same way you likely positioned them in the original orientation, for example by setting their frame.
As for where in code to do this, check out the various orientation change methods of UIViewController that will be called when the device orientation changes. You could, for example, move/resize the controls in the view within willAnimateRotationToInterfaceOrientation:duration:.

iOS SDK UIViewContentModeScaleAspectFit vs. UIViewContentModeScaleAspectFill

I have an image that I would like to display in a UITableViewCell using the UITableViewCellStyleSubtitle style that provides a UIImageView, and two lines of text, plus an optional accessory view.
However, when I set the content mode of the UIImageView to either of UIViewContentModeScaleAspectFit or UIViewContentModeScaleAspectFill, it appears to make no difference. Both of these content modes simply display the entire image, shifting the text to the right to make room for the image.
Does anyone have any examples of how these actually differ in practice? The docs say:
UIViewContentModeScaleAspectFit:
Scales the content to fit the size of the view by maintaining the aspect ratio. Any remaining area of the view’s bounds is transparent.
UIViewContentModeScaleAspectFill:
Scales the content to fill the size of the view. Some portion of the content may be clipped to fill the view’s bounds.
But these content modes don't appear to be behaving as advertised.
EDIT: I'm running SDK iOS 4.
I had the same problem.
Seems like the Apple documentation is a bit lacking.
I found the answer by searching around the internet.
http://www.iphonedevsdk.com/forum/iphone-sdk-development/2973-crop-image.html
Basically,
img1.contentMode = UIViewContentModeScaleAspectFill;
img1.clipsToBounds = YES;
If you want it to be a bit more fancy, check out this post:
UIImageView change Width and Height
The reason you don't see a difference between those modes is that the UITableViewCell automatically sizes its image view to fit the aspect ratio of the image. The content modes only come into play when the view's aspect ratio is different from the image's.
Either override layoutSubviews in your custom UITableViewCell class or create an image view yourself (don't use the one that the table view cell provides).

Smooth scaling when adding/removing subviews to/from a UIView

I'm using a subclass of a UIView to (programmatically) contain and manage numerous subviews (mostly UIImageViews) that are to be positioned adjacent to each other such that none are overlapping. It's safe to assume that the subviews are all the same height (when originally drawn), but are varying widths. The container might be resized, in which case I want the subviews to be scaled proportionally. Moreover, there are times when I need to add/remove/edit any given subview (which might change its width).
I'm had some success in using:
[self setAutoresizesSubviews:YES];
[self setAutoresizingMask:(UIViewAutoresizingFlexibleLeftMargin |
UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleRightMargin |
UIViewAutoresizingFlexibleTopMargin |
UIViewAutoresizingFlexibleHeight |
UIViewAutoresizingFlexibleBottomMargin)];
to have the container automatically resize its subviews when its frame changes.
Unfortunately, I'm having a lot of trouble dealing with the case when the contents of a subview changes, causing it to widen or contract. Simply setting 'setNeedsLayout' and defining 'layoutSubviews' for the subview doesn't seem to do the trick because, at the beginning of 'layoutSubviews' the subview's frame hasn't been adjusted. If I force it, then the current contents are stretched or contracted, which looks terrible.
I'd certainly appreciate it if someone could explain how sizeToFit, layoutSubviews, sizeThatFits:, setAutoresizesSubviews:, setAutoresizingMask:, and setContentMode: should be used in a case like this. I mean, if I want to adjust the contents of a subview (and widen it), then how do I do it such that:
the subview is widened (without adversely stretching or autoresizing anything else within it)
the container is widened a proportional amount
none of the other subviews are affected
?
Thanks in advance!
I ended up going the manual route, using sizeThatFits: and layoutSubviews to explicitly control how everything was redrawn and organized. I found that setAutoresizesSubviews: and setAutoresizingMask: helped for simple layouts, but that it was hard to debug if I tried anything even slightly atypical.
My advice: the first time you're experimenting with programmatic layouts define sizeThatFits for all of your (sub) views and define layoutSubviews for each. Use debugging statements to log the placement of everything. Once you're happy, consider incorporating autoresizing to simply your code (if possible).
For animating the resizing of a view do:
[UIView beginAnimations:#"resizeAnimation" context:nil];
youView.frame = newFrame;
[UIView commitAnimations];
If you don't want an element to resize automatically, just set its autoresize to UIViewAutoresizingNone.
If I get your case correctly, you don't want the containter and its subviews to resize automatically, except the subview you mention. That view should have some autoresizing options enabled (I don't know exactly the ones you want, just try some and see their effect). That subview should also have its subviews resizing disabled.