Reputation: 1048
I have a view that needs different constraints between the iPad & iPhone version.
The login screen is presented as full screen on iPhone & in a page sheet on the iPad. Due to size the UITextFields are 40 pixels away from the right and left sides on the iPhone, but I want them to be 80 pixels on the iPad. I set this as a specific constraint for the Final Values Size Class (w Regular, h Regular).
However because this view appears on a page sheet it doesn't use the Final Values Size Class. Ideally I would like to "force" the view to use a size class, rather than having an array of iPhone/iPad constraints and lots of constraint Outlets.
Upvotes: 4
Views: 3832
Reputation: 2770
The way this is meant to be accomplished is with trait collections on UIViewController, easily by calling -setOverrideTraitCollection:forChildViewController:
.
However, as the API title indicates, a UIViewController can only have its traitCollection overriden by its parent. Presented View Controllers aren't children of their parent (the header file specifically notes presented view controllers aren't included in Child View Controllers) so you will have to add a "ToPresentViewController".
In this example, in IB there is ToPresentViewController
scene that is only a container ViewController attached to its sides with constraints of 0, and the view controller that will be presented embedded.
@implementation ToPresentViewController
-(void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
[super traitCollectionDidChange:previousTraitCollection];
if(thisDevice.userInterfaceIdiom != UIUserInterfaceIdiomPad)
{
return;
}
for (UIViewController *controller in self.childViewControllers) { //Should be only one
UITraitCollection *regularWidthTraits = [UITraitCollection traitCollectionWithHorizontalSizeClass:UIUserInterfaceSizeClassRegular];
[self setOverrideTraitCollection:regularWidthTraits forChildViewController:controller];
}
}
This will lock the size class to regular on iPad.
EDIT: The WWDC sample code here suggests indicates only the overridden traits need to be provided, which makes sense because in the original answer with a old+new merged collection it wasn't clear how it knew which to use.
Upvotes: 8
Reputation: 2770
The way this is meant to be accomplished is with trait collections on UIViewController, easily by calling -setOverrideTraitCollection:forChildViewController:
.
This means you will need to have your view here actually be an explicit child view controller, which has been the recommended practice for a while (and actually can be beneficial in other ways), and I think it might be automatic, but if not there are ways for the parent/child relationship to blend nicely with presenting/presented view controller relationship.
You will also need to make sure to create the trait collection correctly, which is described in the introduction in the UITraitCollection Class Reference
EDIT: This answer by Nick Lockwood, who wrote Core Animation Advanced Techniques, says "That's not how it's supposed to be used" BUT that answer is from 2012/iOS 5, and since then View Controller presentation has been streamlined and size classes (and the methods specifically to override them) have been introduced.
I think you could make the view controller a child and -setOverrideTraitCollection:forChildViewController:
on it as or before you present it. In a worst case you could create a generic UIViewController, embed yours inside it as a child and present that. Let us know if any of these techniques work for you.
Upvotes: 1