I'm writing a program that detects a change in orientation of the device (portrait to landscape, etc.). When the device is in portrait a collectionview should be displayed and a scrollview should be hidden. When the device is in landscape mode the collectionview should be hidden and the scrollview should be displayed.
Through NSLogs I have confirmed that rotating the device is detected. and the hidden property is being set to YES.
I has essentially the same code working with two scrollviews, but due to performance issues I switched to using a collectionview and now it doesn't work. Any advice would be much appreciated. Thank You!
I have this code in the viewDidAppear method:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(detectOrientation) name:#"UIDeviceOrientationDidChangeNotification" object:nil];
And this code in the detectOrientation method
-(void) detectOrientation {
if (([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeLeft) ||
([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeRight)) {
[myCollectionView setHidden:YES];
myPanoramicScrollView.hidden = NO;
NSLog(#"collectionView.hidden = %hhd", myCollectionView.hidden);
} else if ([[UIDevice currentDevice] orientation] == UIDeviceOrientationPortrait) {
myPanoramicScrollView.hidden = YES;
[myCollectionView setHidden:NO];
NSLog(#"collectionView.hidden = %hhd", myCollectionView.hidden);
}
}
Related
Can any one help, the code below works from the portrait view when the app starts, if i rotate to landscape if works great and shows the new view, but when rotate back to portrait, instead of getting the original view, I just get a crash, many thanks
`
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self enableRotation];
}
- (void)didRotate
{
[self setNeedsStatusBarAppearanceUpdate];
if ([UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeLeft ||
[UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeRight) {
[self performSegueWithIdentifier: #"segueToNumbers"sender: self];
}
else if ([UIDevice currentDevice].orientation == UIDeviceOrientationPortrait ||
[UIDevice currentDevice].orientation == UIDeviceOrientationPortraitUpsideDown){
[self performSegueWithIdentifier: #"segueToChoose"sender: self];
}
}
- (void)enableRotation
{
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didRotate)
name:UIDeviceOrientationDidChangeNotification
object:nil];
}
`
Do not respond to rotation events. You need to design you UI with AutoLayout to adjust to different screen size. in iOS 8 the orientation is irrelevant, your code should consider size classes instead
UIDeviceOrientationDidChangeNotification is calling multiple times when the device changes orientation. I am unsure why this happens or how to fix it.
What I am trying to do is to keep the contentoffset of the scrollview the same, so when the user rotates the screen the app keeps the page they were on.
The odd thing is when I rotate the screen the first time the code executes like I would want. But every time after that the code executes multiple times and eventually the contentoffset is set o 0.
Here's what I have.
- (void)loadView {
//some code that sizes itself depending on the current orientation
//WILL BE CALLED AFTER EVERY ORIENTATION CHANGE
}
- (void)viewDidLoad {
//begin generating messages
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter]
addObserver:self selector:#selector(orientationChanged:)
name:UIDeviceOrientationDidChangeNotification
object:[UIDevice currentDevice]];
//if is portrait and was landscape
if (orientation==1 && temp==2) {
int cal = offsetHolder.x/screenframe.size.height;
offsetHolder.x = cal * screenframe.size.width;
ScrollView.contentOffset = offsetHolder;
}
//if is landscape and was portrait
if (orientation==2 && temp==1) {
int cal = offsetHolder.x/screenframe.size.width;
offsetHolder.x = cal * screenframe.size.height;
ScrollView.contentOffset = offsetHolder;
}
}
On orientation change I change the value of 'int orientation' then call loadview to change the sizing of the view. Then I call viewdidload to get the proper contentoffset
- (void) orientationChanged:(NSNotification *)note {
CGRect screenframe = [[UIScreen mainScreen] bounds];
//holding the current offset
offsetHolder = ScrollView.contentOffset;
if ([[UIDevice currentDevice] orientation] == 1 || [[UIDevice currentDevice] orientation] == 0 || [[UIDevice currentDevice] orientation] == UIDeviceOrientationPortraitUpsideDown) {
temp=orientation;
orientation = 1;
[self loadView];
[self viewDidLoad];
}
else if ([[UIDevice currentDevice] orientation] == UIDeviceOrientationFaceDown || [[UIDevice currentDevice] orientation] == UIDeviceOrientationFaceUp){
temp=orientation;
}
else{
temp=orientation;
orientation = 2;
[self loadView];
[self viewDidLoad];
}
}
EDIT:
I have found the problem. What I am doing is creating another instance of self.view instead of overwriting this one. Is there an easy way to destroy this view and re-initialize it?
EDIT2:
Have found a fix. I stopped calling loadview and viewdidload as per jsds' instructions. And instead moved all code in my loadview to another function that I called from loadview. All this code does is instantiate the UI (initview) objects and places them in the correct places depending upon orientation.
Then I create another function that removes all subviews from the view. Then on orientation change I call this function and my initview to destroy all subviews and then recreate them on orientation change.
UIDeviceOrientation basically has 6 different states, namely two portrait, two landscape, and face up and face down. So lets say when you pick up your device from flat position to vertical position, the notification will be triggered.
You can filter the faceup, facedown, and unknown states by using the macro UIDeviceOrientationIsValidInterfaceOrientation
UIDeviceOrientation currentOrientation = [[UIDevice currentDevice] orientation];
// Ignore changes in device orientation if unknown, face up, or face down.
if (!UIDeviceOrientationIsValidInterfaceOrientation(currentOrientation)) {
return;
}
If you still find the notification getting triggered multiple times, I am afraid you may need to use your custom logic with flags to check the previous and current value.
In my case, since I use reactive cocoa framework, the following code works for me :
if (IS_IPAD) {
#weakify(self);
[[[[[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIDeviceOrientationDidChangeNotification object:nil]
takeUntil:[self rac_willDeallocSignal]]
map:^id (NSNotification *notification) {
return #([[UIDevice currentDevice] orientation]);
}]
filter:^BOOL(NSNumber *deviceOrientationNumber) {
UIDeviceOrientation currentOrientation = [deviceOrientationNumber integerValue];
//We ignore the UIDeviceOrientationUnknown, UIDeviceOrientationFaceUp and UIDeviceOrientationFaceDown
return UIDeviceOrientationIsValidInterfaceOrientation(currentOrientation);
}]
distinctUntilChanged]
subscribeNext:^(id x) {
#strongify(self);
//do something here...
}];
}
Here the distinctUntilChanged method makes sure the code gets triggered only when the orientation changes to a new valid value.
You should never call loadView or viewDidLoad yourself. That's up to the framework to manage.
If you are positioning or resizing views based on the view bounds in viewDidLoad, don't. Move that to viewWillLayoutSubviews. That will be called automatically when the device orientation changes.
Alternatively, use autolayout constraints and then you won't have to do anything at all.
I have a Navigation controller that takes a user to another view and lays out the new view based on which button the user clicked on and the orientation. I have a method called layout and I call this method in viewDidLoad, viewWillAppear, and willAnimateRotationToInterfaceOrientation
However, when the view is first loaded, the app does not recognise it's in Landscape. The code I have is:
UILabel *shareLabel = [[UILabel alloc] initWithFrame:CGRectMake(488, 90, 179, 30)];
if (UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation)) {
shareLabel.frame = CGRectMake(543, 90, 238, 30);
}
I've even tried putting a break point on the if statement, and when it gets to the if statement, it steps over it, which tells me it's not recognising that it is landscape? Any ideas on why this would be?
Check this out
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
if ( ([[UIDevice currentDevice] orientation] == UIDeviceOrientationPortrait) )
{
// do something for Portrait mode
}
else if(([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeRight) || ([[UIDevice currentDevice] orientation] == UIInterfaceOrientationLandscapeLeft))
{
// do something for Landscape mode
}
I do some custom layout including an animation in willAnimateRotationToInterfaceOrientation:duration:
The problem I have is that if the device changes from landscapeLeft to landscapeRight the interface should rotate but the layout code, especially the animation should not be run. How can I detect that it is changing from one landscape to another? self.interfaceOrientation as well as [[UIApplication sharedApplication] statusBarOrientation] don't return valid results, they seem to think the device is already rotated. As a result the following does not work.
if (UIInterfaceOrientationIsLandscape(toInterfaceOrientation) && UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]) {...}
You can check the device orientation and then set a flag as to whether you are in left orientation or right orientation. Then when your device switches you can catch it and handle it however you want.
To determine orientation use:
if([UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeLeft)
{
//set Flag for left
}
else if([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeRight)
{
//set Flag for right
}
You can also catch a notification when the device is rotating using:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(detectOrientation) name:#"UIDeviceOrientationDidChangeNotification" object:nil];
And then write a method for detectOrientation like so:
-(void) detectOrientation
{
if ([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeLeft)
{
//Set up left
} else if ([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeRight)
{
//Set up Right
} else if ([[UIDevice currentDevice] orientation] == UIDeviceOrientationPortrait || [[UIDevice currentDevice] orientation] == UIDeviceOrientationPortraitUpsideDown)
{
//It's portrait time!
}
}
-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
if ([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeLeft || [[UIDevice currentDevice] orientation ]== UIDeviceOrientationLandscapeRight)
{
NSLog(#"Lanscapse");
}
if([[UIDevice currentDevice] orientation] == UIDeviceOrientationPortrait || [[UIDevice currentDevice] orientation] == UIDeviceOrientationPortraitUpsideDown )
{
NSLog(#"UIDeviceOrientationPortrait");
}
}
It seems that the only solution is to cache the last orientation change. By the time willAnimateRotationToInterfaceOrientation: is called the device and interface orientations have already been updated. The solution is to record the destination orientation at the end of each change so that this value can be queried when the orientation is set to change again. This is not as elegant as I was hoping (yet another property on my view controller) but seems to be the only way as far as I can tell.
a noob question here.
i detect the orientation with:
UIInterfaceOrientation orientation = [[UIDevice currentDevice] orientation];
all is fine and dandy and I reposition my text fields and labels according to the reported orientation with
if (orientation == UIDeviceOrientationPortrait || orientation == UIDeviceOrientationPortraitUpsideDown)
and else{} for everything else
the problem that i only recently discovered is when the UIDevice reports UIDeviceOrientationFaceUp or UIDeviceOrientationFaceDown. how do I deal with this situation ? how do I know whether UIDeviceOrientationFaceUp and UIDeviceOrientationFaceDown is happening in Portrait or Landscape ? I know that the device is facing up or down, but I don't know if I should reposition everything to Portrait or Landscape.
thank you!
Apple recommends against using device orientation for view layout. Instead, each view controller has an interfaceOrientation property, and UIApplication has a statusBarOrientation property, both of which will return the current interface orientation, which is suitable for view layout.
To monitor for changes, there are UIViewController methods like willRotateToInterfaceOrientation:duration: that will be called and notifications such as UIApplicationWillChangeStatusBarOrientationNotification that will be posted when an interface orientation change occurs.
A bit late, hopefully it would help some one.
For iOS 6.0 and later:
1) Set this code during your View Setup to receive rotation notification:
// Set Listener to receive orientation notifications from the device
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(detectOrientation)
name:UIDeviceOrientationDidChangeNotification
object:nil];
2) Set this code to catch the Notification after rotation:
-(void)detectOrientation{
switch ([[UIDevice currentDevice] orientation]) {
case UIDeviceOrientationFaceDown:{
NSLog(#"UIDeviceOrientationFaceDown");
break;
}
case UIDeviceOrientationFaceUp:{
NSLog(#"UIDeviceOrientationFaceUp");
break;
}
case UIDeviceOrientationLandscapeLeft:{
NSLog(#"UIDeviceOrientationLandscapeLeft");
break;
}
case UIDeviceOrientationLandscapeRight:{
NSLog(#"UIDeviceOrientationLandscapeRight");
break;
}
case UIDeviceOrientationPortrait:{
NSLog(#"UIDeviceOrientationPortrait");
break;
}
case UIDeviceOrientationPortraitUpsideDown:{
NSLog(#"UIDeviceOrientationPortraitUpsideDown");
break;
}
case UIDeviceOrientationUnknown:{
NSLog(#"UIDeviceOrientationUnknown");
break;
}
default:{
break;
}
}
}
I have the same problems with
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
This method generate notifications for 7 possible device positional states:
UIDeviceOrientationPortrait
UIDeviceOrientationPortraitUpsideDown
UIDeviceOrientationLandscapeLeft
UIDeviceOrientationLandscapeRight
UIDeviceOrientationFaceUp
UIDeviceOrientationFaceDown
UIDeviceOrientationUnknown
But I only need the first 4, well this is my approach to solve this problem (with code included):
How to handle UIDeviceOrientation for manage views layouts