How To Reposition Elements On Device Rotation In Xcode 5? - ios

I'm working on an application that should support both portrait and landscape orientations. There is no problem with using auto layout for re arranging the controls in the view but there is something that i cannot do with auto layout. I have two views under each other in the portrait view and i want them to be next to each other in landscape view. I can move the bottom view in the right X position but it is still under the top view. this picture describes what i want to do:
http://www.hesamstore.ir/Orient.png
How Can I Do This?
Thanks for reading.

Add constraints to all the IBOutlets.
add Constraints - 1. Height,width, Trailing and leading , and that would solve it,
If you want accurate ratio then select two outlets and add horizontal constraints with a ratio.
And also select a label and its corresponding switch and add horizontal spacing and do it to EQUAL.
Yup that should do it.

just implements this method to your code...
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
BOOL isPortrait = UIDeviceOrientationIsPortrait(self.interfaceOrientation);
if(isPortrait == NO)
{
// this is landScape mode....
// here give the frames that you want for your controls...
}
if(isPortrait == YES)
{
// this is portrait mode....
// here give the frames that you want for your controls...
}
}

Related

Hiding a view when orientation changes to landscape in autolayouts

I am creating a sample application in which i am copying Facebook screens in order to practice auto layouts.
When I run login screen in portrait mode, it looks perfect.
The problem is as soon as the orientation changes to landscape, all the views collapse because of header image, as shown here
What i want is that, in landscape mode, header image disappears so that other views get its space. I don't want to use scrollview.
I tried this:
headerImageView.isHidden = true
But the result came out to be this
The imageview got disappeared but didn't leave its space.
Can anyone suggest me a good solution?
P.s
Sorry for the images being this way because of my reputation.
When using Auto Layout you can leverage Size Classes.
See description below or example here: https://github.com/jonaszmclaren/AutolayoutExample
Set image view for compact width and height (wC hC - iPhone in landscape) and for wR hC (iPhone Plus in landscape) to not installed:
Constraint between text field and image view not enabled for wC hC and wR hC:
And finally for wC hC and wR hC you have to define text fields's top contraint - I did it to the top of the view.
This way, image view for portait will be visible and text view pinned to image view, and in landscape image view will be hidden and text field pinned to top of the view.
The best way is to use scrollView in such type of scenarios. If you don't want to have the scrollView, then you must give the bottom constraint for last button, and set the priority low of that particular constraint. It will work fine for current screen(both landscape and portrait), but when you'll go for small screen i.e 4s or 5, then purpose of auto layout will fail.
If you hide the image than it will only not show to user But Space will be used by Image on screen. Better Approach is you can set the Height Of Image 0 when orientation change to Landscape. You can create the Outlet of Height Constraint of Image and Change it according to Orientation.This method is called before orintation change. You need to Create outlat of Height constraint of Image.
#IBOutlet var heightConstraint : NSLayoutConstraint!
override func willRotate(to toInterfaceOrientation: UIInterfaceOrientation, duration: TimeInterval)
{
if toInterfaceOrientation == .landscapeLeft || toInterfaceOrientation == .landscapeRight{
// Imageview height constraint outlate
heightConstraint.constant = 0
}
else{
heightConstraint.constant = 100
}
}
isHidden will just changed the visibility of the view. It will not remove it from that position. To solve this issue create a outlet of height constraint of header view and changed it to 0 on orientation change.
ex:
headerViewHeightConstraint.constant = 0.0
self.view.layoutIfNeeded()
and to restore it on portrait mode set height again.
headerViewHeightConstraint.constant = // height value which you want to set
self.view.layoutIfNeeded()
Another option could be to place your view inside a stack view. Then hiding the headerImageView should recover the unused space.

iOS UIView Not Resizing Subviews?

I'm loading a view from a storyboard programatically, but there's an issue with my subview heights (I'm using Autoresize Subviews etc).
When the view loads, the main UIView appears to be the correct size, but the subviews that depend on the constraints to dynamically calculate their final height don't seem to be resizing from the sizes they were set at in interface builder.
Loading the view like so:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
ApplicationRecordingViewController* recordingController = (ApplicationRecordingViewController*)[storyboard instantiateViewControllerWithIdentifier:#"recordView2"];
[self presentViewController:recordingController animated:NO completion:nil];
Orange area's height is from top of main view to top of grey area. Grey area is fixed height
The strange thing is, if I set the simulated size in interface builder as the correct view for my phone, the sizes work out. I guess the initial heights for subviews are 'baked' into the view, but then (usually) resized when the view actually loads?
Note: The orange area should be completely filled by the camera view I'm loading into it.
Incorrect height
Correct height if I change simulated layout
Would love to know what I'm doing wrong!
Edit 1: Constraints
Camera is the orange bit. The Camera bottom constraint is currently set as the bottom of the view + enough room for the gray bar. Have also tried setting the bottom to match the top of the gray bar!
Link to Storyboard with Scene
I know you're all better than me, but I experienced the same in my last project. My Camera View inside a UIView is not in full screen or resizing and fitting the whole UIView, and I also posted it on my daily blog.
Implement viewDidLayoutSubviews -- Inside that method, layout again your video preview layer.Do not alloc init anything inside that method, just re-layout your views. After that, your video preview will fill the height and width of its parent, or whatever you've been targetting.
The issue also has something to do with the hierarchy of the constraints and views.
You already got the answer.
'if I set the simulated size in interface builder as the correct view for my phone, the sizes work out.'
You may call some functions to get height in viewDidLoad or viewWillAppear.
Change Code like this
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.view setNeedsLayout];
[self.view layoutIfNeeded];
CGFloat height = [self getHeight];
}
or
- (void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
CGFloat height = [self getHeight];
}
As i can see in your storyboard constrain you have set bottom space to bottom layout guide 150 . i think this is the issue . if you give fixed height to bottom view then no need to set constant as from bottom layout guide --> 150 .
Your old constrain :- >
Just set bottom space of orangeview from greenview = 0.
Check new constrain ,
Here is your storyboard link ,
Storyboard Download link
Here is your output,
After investigating the layout a little more, I found the camera view (orange) seemed to be the correct size, but the live camera preview wasn't.
Solution was to move the camera library (SCRecorder)'s init method into viewDidAppear (was in viewDidLoad before).
My thinking is iOS doesn't autolayout the camera preview view in the same way as normal UIViews, etc.
#interface ApplicationRecordingViewController () {
SCRecorder *_recorder;
}
#end
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
_recorder.previewView = _previewView;
}
Perhaps you can try to get rid of these two hook.

How to change UIView constraints based on device orientation using Objective C?

I am trying to create iOS storyboard with multiple view for portrait and landscape. Everything I have created storyboard constraints and autolayout.
Now my problem is for portrait I need to show like below portrait Image. Thats I have done by using storyboard constraints.
For landscape Need to show First View (red) and bottom bar only other I have hidden by hardcode. But I don't know how to expand the red screen first view full height upto bottom bar top.
NOTE : This is Universal App.
- (void) orientationChanged:(NSNotification *)note
{
UIDevice * device = note.object;
switch(device.orientation)
{
case UIDeviceOrientationPortrait:
/* start special animation */
NSLog(#"Portrait");
self.namelist_tableview.hidden = NO;// ORANGE VIEW
break;
case UIDeviceOrientationLandscapeRight:
/* start special animation */
NSLog(#"Landscape");
self.namelist_tableview.hidden = YES;// ORANGE VIEW
break;
case UIDeviceOrientationLandscapeLeft:
/* start special animation */
NSLog(#"Landscape");
self.namelist_tableview.hidden = YES;// ORANGE VIEW
break;
default:
break;
};
}
Very simple, add constrains in intefacebuilder for portrait mode ,
add constrains for landscape mode.
Next make an outlet for all constrains.
In device change orientation event do this
if you are in landscape mode
+Set active constrains for portrait to false (constraint.active = NO)
+Set active of constrains for landscape to true (constraint.active = YES)
if you are in portrait mode
+Set active of constrains for landscape to false (constraint.active = NO)
+Set active of constrains for portrait to true (constraint.active = YES)
you can add the red view height constraint, store it in your UIViewController.
when the device's orientation changed. if portrait, set the ret view height constraint equal how long you want to set, and landscape set the red view height constraint your initial value.
It can be done easily if you use size classes.
Use cmd+delete for the views which you don't want in landscape mode.and set others accordingly.
If you did not fix the height of the red view than you can do something like this:
Create a instance of height constraint of the yellow color view like,
Step 1: Select height constraint as I did
-
Step 2: Make a instance in you view controller interface
After that write below line of code to your orientationChanged: method
self.heightConstarintYelloView.constant = 0.f;
It will set you yellow box height to zero and because of the vertical spacing between red view and yellow view, red view will than expand.

How to configure different layouts for Portrait and Landscape Orientations using Auto Layout?

I have a view like in attached image
Now I am adding constraints such that the UITextview in the view has to be on the right hand side of the screen when orientation is changed to landscape. On UItextview, I have added below constraints,
Trailing Space to : Superview
Bottom Space to : Superview
These constraints though displayed some warnings on ambugity, did the job for me. Below is the screenshot of landscape mode.
My problem is though the UItextview is moved to right side, I want some additional width from top of superview when it is in landscape mode. In other words, I want the UITextview to be moved a little downward from where it is now in landscape mode. I am pondering how to do that using auto layout in IB and I am not able to figure that how.
Any suggestions please.
You can do this with constraints in several ways, but there's no way to do this automatically with just constraints you make in IB. By using both the multiplier and constant values in the method, constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:, you can have one constraint that evaluates to different distances in portrait and landscape. It's a pain to do the calculations to figure out what to use for those values, so I've written a category on NSLayoutConstraint to do that. An example of one of those methods, is this:
+(NSLayoutConstraint *)topConstraintForView:(UIView *)subview viewAttribute:(NSLayoutAttribute) att superview:(UIView *)superview portraitValue:(CGFloat)pValue landscapeValue:(CGFloat)lValue {
CGFloat multiplier = (pValue - lValue)/(superview.bounds.size.height - superview.bounds.size.width);
CGFloat constant = pValue - (superview.bounds.size.height * multiplier);
NSLayoutConstraint *con = [NSLayoutConstraint constraintWithItem:subview attribute:att relatedBy:0 toItem:superview attribute:NSLayoutAttributeBottom multiplier:multiplier constant:constant];
NSLog(#"top coeffs: %f %f",multiplier,constant);
return con;
}
The way you use these, is to add the starting portrait constraint in the storyboard, but check the box, "Placeholder - Remove at build time" in the attributes inspector for the constraint, and then replace it in viewDidLoad, like this:
- (void)viewDidLoad {
[super viewDidLoad];
[self.view addConstraint:[NSLayoutConstraint topConstraintForView:self.textView viewAttribute:NSLayoutAttributeTop superview:self.view portraitValue:225 landscapeValue:50]];
}
This will automatically adjust the position of the text view based on the rotation of the device without any further code. You might have to change the width of the text fields to get everything to fit properly -- I enclosed them and the "Get" labels in a view to more easily position them as a group. That view and the text view had height and width constraints, as well as top and left for the view, and top and right for the text view. The category has methods to adjust the other constraints as well, and can be found at http://jmp.sh/b/S4exMJBWftlCeO5GybNO.
The other way to do this, is to make IBOutlets to the constraints you make in IB, and adjust them (the constant value), or delete some and remake other ones, in one of the rotation callback methods.

Vertical centering view, autoresizing and iPhone 5 4" screen

I have some custom buttons I add to the view in -viewDidLoad. I want them centered vertically inside the view, like so:
self.customButton.center = CGPointMake(98.f, self.view.center.y);
However, the view height is 504.0 even on a 3.5" device, where I expect it to be 416 (480 - 20 (status bar height) - 44 (nav bar height)).
The view in xib is using "Retina 4 Fullscreen", but setting it to freeform does not help. I certainly don't want two xibs just to account for the height difference.
I know I can use UIScreen but I would prefer that the view be aware of the height difference.
EDIT: the odd thing is, in -viewWillAppear, view height is correctly set to 416.0. Why this isn't handled after [super viewDidLoad] is beyond me.
How are people handling this? Autolayout would probably handle this but I need a iOS5 compatible method. Can autoresizing handle "centering" somehow?
You don't have Autolayout in iOS5, but you do still have the autoresizing mask. If you center a view vertically in IB, go to the inspector and deselect the vertical struts and springs in the autolayout masks, the view will stay centered vertically on both 4" and 3.5" screens.
Or you can do this in code in your viewDidLoad method. Just center the view as you are now and set the autoresizingMask like this:
self.customButton.autoresizingMask = (UIViewAutoresizingFlexibleBottomMargin | \
UIViewAutoresizingFlexibleTopMargin);
EDIT: the odd thing is, in -viewWillAppear, view height is correctly set to 416.0. Why this isn't handled after [super viewDidLoad] is beyond me.
Because resizing the view is not part of loading the view! -viewDidLoad gets called from -view in a method that probably looks a bit like this:
-(UIView*)view
{
if (!_view)
{
[self loadView];
[self viewDidLoad];
}
return _view;
}
-(void)loadView
{
// Some code to load the view from a nib/storyboard...
}
The view will get resized with a call like yourViewController.view.frame = ..., but this can only happen after the view is loaded (and thus after -viewDidLoad is called).
Set some autoresizing masks. That's what they're there for.

Resources