Auto resizing UITableView on rotation with flexible width - ios

I am adding UIButtons to a UIView located on the right side of a split view controller. Without any autoresizing set, the button text fully displays in landscape orientation. When I rotate to portrait orientation, all button text is fully displayed, but there is extra space on the right hand side of the UIView, because there is more real estate to work with.
I would like these buttons to resize on rotation so that it utilizes the entire width. I tried setting:
[button setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
With this in place, the same extra real estate exists on the portrait orientation, but in landscape orientation I get a lot of buttons with the text shortened with "..."
How can this be done?

when the AutoResisingMask doesnt do it for me, I always resort to subclassing the UIView and overriding the layoutSubviews... this way I can manually place those tricky views that never look right in different orientations.
in fact.. at last year's WWDC, I heard an Apple Engineer say that he "always" creates and adds his views with frame CGRectZero, then sets the correct frame in layoutSubviews. For what its worth...

Related

UITableViewHeader doesn't maintain position when device rotates

I seem to be having issues with my UITableViewHeaderView not maintaining its position at the top when the device rotates. What seems to be happening is once the device rotates to landscape, the header completely disappears at the top. When I then rotate it back to portrait, the header seems to become massive and not reset to its original size. The header itself has imageviews and labels laid out inside the view using auto-layout.
Is there a way to adjust the header to stay where it is when the device rotates? I've tried looking at other questions but can't find a solution.
Some thing to try is to use UITableViewHeaderFooterView and put the content inside the contentView property.

Finer grained UIView rotation in a UIViewController

I have a UIViewController that overlays controls on a view presenting what the camera sees. I have a couple of scenarios I would like to allow.
For the iPad, I want to keep the controls on the right most edge of the device, by your right thumb, no matter what the device's rotation. The controls should rotate their content so that their top is always upwards (away from the ground). I don't want the camera view to rotate at all, because that would just be silly – its position & size should stay the same and its contents shouldn't rotate either.
For the iPhones, I want to keep the controls at the bottom of the device's screen, by to the home button, wherever the home button actually is. The controls should rotate their content so that up is always pointing upwards. Again, I don't want the camera view's frame or content to take part in any view rotation animation at all.
I'm using auto-layout.
I'm wondering if there is any way to describe some or all of this in a storyboard. In particular, it'd be great to be able to describe that some view positions need to autorotate (ie, the controls, on iPad), but that other views don't (the camera view).
A question from 2011 indicates this wasn't possible at the time, but perhaps things have moved on since then? If it's not directly supported, can you suggest an approach and are there some sensible places to be hooking in to autorotation to achieve this?
Ok, this isn't quite a complete answer, but I tried a few things which look promising.
First, you can create a separate set of constraints for portrait vs. landscape using the size specifiers: landscape is w Regular, h Any; portrait is w Any, h Regular (I think -- double-check these) This is accessible via the pop-up control in the bottom-center of the storyboard view. By installing different constraints for portrait and landscape, it should be possible to scale the width and height of your controls' container view so it appears to be in a constant position w.r.t. device orientation; in other words, the container doesn't actually counter-rotate -- it scales so it effectively looks like it has counter-rotated.
I got this close to working. It looks like it's doing the correct thing in the storyboard view, but when I actually run it, I get debug messages about conflicting constraints. Not sure how to fix this, but maybe play with the constraint priorities? That sometimes helps.
A second thing I (partially) tried was creating a custom container view class which counter-rotates itself to the correct position based on the device orientation (in the UIDevice class). You implement this by overriding layoutSubviews. For each orientation, you define a transform which puts it in the correct position, and set the view's transform property.
Another possible solution is to override updateConstraints in your view controller and add/remove constraints to position/scale your container to the correct place for each orientation.
For all of these, the idea is that you "force" the container to be in the correct place, but leave the subviews (the actual controls) alone. The controls should do the right thing if their constraints are independent of the specific orientation of the container view.
So, those are some ideas anyway... if they lead you to an actual solution, could you post it? I anticipate having a need for this myself.

Using AutoLayout to just rotate a View

With AutoLayout, is it possible to keep a View (button, image, etc) in the same location but just rotate it 90 degrees when the device is rotated?
For example, in the following images the Views stay exactly as they were placed in the portrait orientation (same distances from the edges), but are rotated in landscape.
You describe the views in the images you've provided as "staying in exactly the same place", but I think this is to misunderstand autolayout and the rotation behaviour. Your layout has changed significantly between the two examples. Where both views were previously aligned along their left edges, now they're aligned along their bottom edges.
Basically: when you rotate the device (lets say from standard portrait to home-left-landscape) you're changing which view is the top, not the direction the top view is pointing.
If you want to recreate the look of the rotated view you provided, you have a few options. I'd suggest looking at the visual formatting language, which is a good way of adding constraints programatically... it's easier then it seems. Take a look at the iOS auto-layout talks from WWDC 2012 if you want a good introduction. You could then add and remove the appropriate constraints when the device rotates. (it might take a bit of playing around). There's also a section in the View Controller Programming Guide on 'creating a custom landscape orientation' that might be helpful.
If you're allowing the interface orientation to rotate, then you'll have to change your constraints on rotation to put the views where you want them.
If you're not allowing the interface orientation to rotate, then you'll have to subscribe to device orientation change notifications. When the orientation changes, you can update the transforms of the views to rotate them. If the views are square, that should suffice. If the views are not square, you also need to modify your constraints based on the rotated frames.

UIPageViewController rotation weirdness

I've added a UIPageViewController to my app to act as a manual for the app. When the user pops it up it shows one page in portrait and two in landscape with the spine in the middle. Since I have about 100 pages, there is a sibling view UICollectionView page selector view above it to allow jumping to a page quickly. Both the UIPageViewController and the UICollectionView sit on a backing view that contains them both.
The problem I am having with the UIPageViewController is that when the views are first rotated they seem to constrain themselves to the short dimension of the original layout. So, if it first appears in portrait, then when rotating to landscape the width of the two pages is the same as the old portrait width. Likewise, if it first appears landscape with two pages, rotating to portrait has the correct width, but the height is the height of the initial landscape height. This is consistent on any device.
When I create my content views they are all the size I desire, but for some reason they seem to be transformed by some component of UIPageViewController and I'm not grasping why it is only doing one of the two dimensions and why it is always the "short side" that is the problem.
This is one of those kinds of problem that makes me feel a bit nutty, any ideas on how I might debug it if it isn't some trivial misconfiguration?
I finally found it after a long period of debugging. The critical hint was seeing that the spine is set to the correct mid for the width of the view BEFORE the rotation for portrait to landscape. The solution was to reset the frame of the view to the new size given the orientation in willAnimateRotationToInterfaceOrientation.
I calculate the new size before I call an animation block that uses the duration passed into the method, then inside the block I have:
pageViewController.view.frame = newFrame;
When the page is rotated the view holding the content pages is shifted to the correct size and the spine is place correctly and the content fills the given area. I suppose that I ran into the problem because the complexity of the views required me to take over so many defaults, but this one was left hanging.

What is the purpose of UIView's autoresizingMask?

After reading about UIView's autoresizingMask on SO and developer.apple.com I'm still unclear what the purpose is. What's a situation where setting this property is necessary?
Yes, it is often necessary to set it if you don't want to resize the views manually. Note that it is mostly useful for subviews (i.e. those views that don't take the whole screen) rather then the main view of your app.
Views typically may need resizing if:
the device is rotated
an extra view (say, an ad) is added to the view, so the existing subviews have less available space.
For example, suppose if you have a view with two buttons on it, one in the top-left corner, another in the top-right corner. In order for the buttons to get wider when the view transitions from portrait to landscape, you need to set the FlexibleLeftMargin to the right button, FlexibleRightMargin to the left button.
Edit: autoresizingMask is also the first thing to look at if you see weird holes or overlaps when device is rotated or a new subview is added. Quite often the proper setting of these masks for subviews can get you a nice looking view in both orientations without having to lay out subviews manually - but usually it takes some experimenting.
Edit2: (since this is still gathering upvotes) Autoresizing masks are now mostly superseded with "Auto Layout", which allows for much more flexible constraints on views' sizes and positions. That being said, translatesAutoresizingMaskIntoConstraints is still occasionally useful for dynamically added views.
The purpose is that UIView properly shifts and resizes when its superview changes due to resizing, orientation change, showing editing controls in tableview cells etc.

Resources