Hiding a view when orientation changes to landscape in autolayouts - ios

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.

Related

how to make buttons in stackview change size depending on screen size (using main.storyboard or code)

I am trying to figure out how to make my three buttons in a stackview have relative sizing and keep the same multiplier spacing on different devices, e.g. the buttons will be bigger if i am on an ipad compared to an iphone. Secondly the spacing between left and right edges of buttons will be bigger on an ipad compared to that of an iphone device. So far I currently have three buttons in a stackview. I have added horizontally and vertical allignment to my stackview. I have played around with adding equal heights and width and changed the multiplier as well as adding constraints to the buttons however it did not get my desired result.
Here is a screenshot of how i'd like my items to be placed on all devices:
UIStackView has only static spacing. You have two options:
Change spacing inside code with viewWillLayoutSubviews. I prefer it over viewDidLayoutSubviews because changes will follow rotation animation. But if your calculations will depend on other subviews(not just self.view), these frames will not be updated yet. You can change constraint.constant like this too.
#IBOutlet var stackView: UIStackView!
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
stackView.spacing = view.bounds.height * 0.05
}
Using only storyboard, you can't add spacing constraint with modifier. But you can add a transparent view which will be your spacer, and apply width/height modifier to it. This can be used both for UIStackView and for plain views.
I prefer adding equal height constraint for all views with same size(like btn1.height = btn2.height, btn1.height = btn3.height), so I can set size with one constraint to all of them(btn1.height = superview.height * 0.1).
Something like this should work for your:
Result:

Unwanted white space on left of UIScrollView on iPhone X

UIScrollView works fine without the white space on the left on all iPads or iPhones except for iPhone X. How can I remove the white space?
I use storyboards. Bounce On Scroll/Zoom are all disabled. No white space on iPad or iPhone except for iPhone X. I think it might be something related to the Safe Area thing.
This spacing is from safe area, which is applied to left/right of UIScrollview as content insets in landscape orientation on iPhone X, which can be seen using read-only property UIScrollview.safeAreaInsets.
Following line can be used to get rid of safe area insets when you dont need:
UIScrollview.contentInsetAdjustmentBehavior = .never
The default value being UIScrollViewContentInsetAdjustmentBehavior.automatic includes safe area layout guide margins as content insets.
Note: auto layout constraints has nothing to do with the insets, its just iOS 11 UIScrollview content insets adjustment behavior.
Setting the constraint relative to safeArea is good practise for iPhone-X.
This is how apple says -
When the view is visible onscreen, this guide reflects the portion of
the view that is not covered by navigation bars, tab bars, toolbars,
and other ancestor views.
In your case you are giving constraints leading & trailing of scrollView with safeArea, Not superView
Hence if you take risk giving constraint to superview instead of safeArea your object content may clipped, specially when you rotate left, content from the left most will clip under top notch of iPhone-X.
Apple doc for safeAreaLayoutGuide
Well, I solved this issue in non-elegant way. But it works like a charm. (I tried all other answers. Thank for your help, however those answers don't seem to work in my case.)
var leftMargin: CGFloat = 0
var rightMargin: CGFloat = 0
if Device.isPhone() && Device.IS_5_8_INCHES() {
self.leftMargin = 44
self.rightMargin = 44
}
let frame = CGRect(
x: (self.view.frame.width - self.leftMargin - self.rightMargin) * CGFloat(pageIndex),
y: ...
)
Safe Area Layout is responsible for this white space.
1st Option:
Ignore safe area layout for your scrollview and set scrollview's constraints with respect to its super view (or main view). Scrollview automatically handle safe area inset for contents while scrolling.
Landscape View:
Portrait View:
2nd Option:
I do not recommend to remove/change safe area layout for your scroll view and an alternate solution that can solve white space visibility issue:
Set blue background color (that you've applied for your scroll view) to your main view of your view controller, if scroll view is covering entire screen.
set clear color background for your scroll view
Add this code in your viewDidLoad
# IBOutlet var scrollView: UIScrollView!
override func viewDidLoad(){
super.viewDidLoad()
self.view.backgroundColor = UIColor.yellow // set here blue color that you've applied for your scroll view
self.scrollView.backgroundColor = UIColor.clear
}
Here are good reference answers regarding Safe Area Layout, for better understanding:
Safe Area of Xcode 9
Use Safe Area Layout programmatically

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.

Adding Views with Equal Width to Superview - Autolayout iOS

I have 3 uiviews which is added to parent view. i want the views (subviews) should have equal width in Portrait and Landscape. You can see three views share equal width in portrait but the centerview takes more space in Landscape. How to make equal width in Landscape.
Landscape:
Portrait:
As far as I can tell, the task is very trivial, you just have to set all horizontal edge relationships (e.g. view1.left = superview.left, view2.left = view1.right, view3.left = view2.right and view3.right = superview.right) as well as make all three views' width equal.
Also, don't forget to make vertical constraints, so vertical positions and heights could be calculated.

How To Reposition Elements On Device Rotation In Xcode 5?

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...
}
}

Resources