Here is the problem I've been struggling with:
I'm creating a view programatically using loadView.
Once it's loaded it looks just great in Portrait view. However, I want to handle rotation of the device. Therefore I use willAnimateRotationToInterfaceOrientation method.
Within this method I call a function that adjust all the elements. What that function does is just goes through all my views and sets new CGRect to each of them. It works just fine on portrait orientations (up and upside-down), but once I change orientation to horizontal, it crops.
Two questions:
What is the most likely reason for such behavior?
How would you suggest handling device rotation without creating a separate view for horisontal / vertical orientations?
I think you are missing the key part. When you are setting the frame at portrait view at view did load, view got the frame but when it change to the landscape it change but again from there i think you are not setting the frame for portrait view. use notification
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(orientationChanged:) name:#"UIDeviceOrientationDidChangeNotification" object:nil];
-(void) orientationChanged:(NSNotification *)notification
{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
UIDeviceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
if((orientation == UIDeviceOrientationPortrait) || (orientation == UIDeviceOrientationPortraitUpsideDown)) {
// set frame here
}else if ((orientation == UIDeviceOrientationLandscapeLeft) || (orientation == UIDeviceOrientationLandscapeRight)){
// set frame here too
}
}];
}
Related
My code is very simple. I want to change the positioning of an SKSpriteNode to always remain in the bottom right corner of the device screen. I call my UIDeviceOrientationDidChangeNotification method "rotated" on device rotation and it should simply move the node, but for some reason it always flips the desired location so the landscape position is where the portrait should be and vice-versa.
My code is as follows:
UI
- (void)rotated:(NSNotification *)notification {
DeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
if (UIDeviceOrientationIsLandscape(deviceOrientation) && !_isShowingLandscapeView)
[self.node setPosition:bottom_right];
_isShowingLandscapeView = YES;
}
else if (UIDeviceOrientationIsPortrait(deviceOrientation) && _isShowingLandscapeView)
{
[self.node setPosition:bottom_right];
_isShowingLandscapeView = NO;
}
}
Ok so what I'm doing is simple. Just use UIButtons over your SKScene. Go back to the UIViewController where you call your skscene from and add buttons. You'll have to use NSNotification center to pass information to the buttons, labels, etc.
http://www.raywenderlich.com/forums/viewtopic.php?f=2&t=8843
I have placed an overlay image over camera view and trying to Capture the image but as soon as I capture the image (I have not tapped the "Use Photo" button yet), the captured image moves some pixel down and the height of top black bar having flash and front/back camera settings buttons suddenly increases. So the situation now is - my overlay image has not moved a single pixel and the captured image has moved downwards. So I am not able to capture the correct image with overlay placed properly. This issue is only in iOS8 and above.
Anybody facing this issue on iOS8 ??
It turns out that for the iPhone (when the UImagePickerController is presented under a navigation controller) the navigation bar is hidden when you take a picture. In the following preview, however, the navigation bar is no longer hidden even if it's not visible and unhiding moves the preview image down or to the right, depending on the orientation. To compensate for this change you'll have to adjust the origin of the camera overlay view accordingly. I resolved this by adding a callback that handles the UIImagePickerController notifications. In your code where you initiate the UIImagePickerController add the following code:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(handleImagePickerNotification:)
name:#"_UIImagePickerControllerUserDidCaptureItem"
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(handleImagePickerNotification:)
name:#"_UIImagePickerControllerUserDidRejectItem"
object:nil];
The callback which handles the notification must distinguish between the UserDidCaptureItem and UserDidRejectItem notifications. In the first case the x- or y-origin of the camera overlay frame is incremented (depending on the orientation), in the second case the increment is reverted again. The size of the increment or decrement is the height of the navigation bar.
- (void)handleImagePickerNotification:(NSNotification *)notification {
// This notification compensates for a feature (?) introduced with iOS 8 that moves the
// image after it's been taken with the UIImagePickerController.
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
CGRect frame = cameraOverlay.frame;
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
CGFloat barHeight = [self.navigationController navigationBar].frame.size.height;
if ([[notification name] isEqualToString:#"_UIImagePickerControllerUserDidCaptureItem"]) {
if (UIInterfaceOrientationIsLandscape(orientation))
frame.origin.x += barHeight;
else
frame.origin.y += barHeight;
} else
if ([[notification name] isEqualToString:#"_UIImagePickerControllerUserDidRejectItem"]) {
if (UIInterfaceOrientationIsLandscape(orientation))
frame.origin.x -= barHeight;
else
frame.origin.y -= barHeight;
[cameraOverlay setFrame:frame];
}
[cameraOverlay setFrame:frame];
}
This isn't a very elegant way of resolving the issue but in my case it worked.
I have a UITextView that in portrait sizes 500px width.
I add it by code as subview but i can't be able in viewdidapper to get the correct size if the app is opened in landscape mode.
After the device rotation it works right. If opened landscape no.
How can i calculate the correct dimension of this textview when opening landscape?
Thank you
Add a notifier in the viewWillAppear function
-(void)viewWillAppear:(BOOL)animated{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil];
}
The orientation change notifies this function
- (void)orientationChanged:(NSNotification *)notification{
[self adjustViewsForOrientation:[[UIApplication sharedApplication] statusBarOrientation]];
}
and you calculate the size of your textView
- (void) adjustViewsForOrientation:(UIInterfaceOrientation) orientation {
if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown)
{
//calculate the portrait textView size
}
else if (orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight)
{
//calculate the landscape textView size
}}
i hope this help
I'm developing an iOS application with latest SDK.
My app only supports Landscape right orientation and it only has one view controller. I set the only available orientation modifying myProject-info.plist.
I'm trying to understand why this code outputs a log for a view in Portrait mode when I only supports landscape right orientation.
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
UIView *videoView = self.videoPreviewView;
NSLog(#"Video frame: %#", NSStringFromCGRect(videoView.frame));
}
Console output:
Video frame: {{0, 0}, {320, 568}}
I'm working with AVCaptureVideoPreviewLayer and I need to set its frame, but when I do it on viewWillAppear: I get portrait values but orientation value is Landscape right.
Is there an event or anything similar that i gets triggered when orientation changes to landscape?
When does the app changes orientation to default orientation?
Go into xCode, and click the project name at the top of the screen (with an xcode LOGO underneath it).
Then reveal the iPhone/Ipad development info and select the orientations you want to be available for users :)
If you add the line:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(orientationChanged) name:UIDeviceOrientationDidChangeNotification object:nil];
then it will call the -(void)orientationChanged; method every time the orientation is changed. You can then do something like:
-(void)orientationChanged {
if (UIDeviceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation) {
//device is portrait;
}
else {
//device is landscape;
}
}
Then you can use this to determine the layout of your views and setup based on the orientation.
EDIT:
You can also check if the orientation returned by the statusBar's orientation is equal to UIDeviceOrientationLandscapeLeft/LandscapeRight/Portrait/PortraitUpsideDown.
I created a UIViewController (based on How to switch views when rotating) to switch between 2 views when the device rotates. Each view is "specialized" for a particular orientation.
It uses the UIDeviceOrientationDidChangeNotification notification to switch views:
-(void) deviceDidRotate: (NSNotification *) aNotification{
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
NSLog(#"Device rotated to %d!", orientation);
if ((orientation == UIDeviceOrientationPortrait) ||
(orientation == UIDeviceOrientationPortraitUpsideDown)) {
[self displayView:self.portraitViewController.view];
}else if ((orientation == UIDeviceOrientationLandscapeLeft) ||
(orientation == UIDeviceOrientationLandscapeRight)) {
[self displayView:self.landscapeViewController.view];
}
}
and sort of works. The problems shows up when I rotate to Landscape and then back to Portrait. When going back to portrait the subviews aren't displayed in the right place, specially the UIPickerView:
First Time Portrait:
Rotate to Landscape:
Back to Portrait:
If I repeat the rotation process, things just get worse. What am I doing wrong?
The source code is here: http://dl.dropbox.com/u/3978473/forums/Rotator.zip
Thanks in advance!
To solve your offset problems, rewrite the displayView: method as below.
-(void) displayView: (UIView *)aView{
self.view = aView;
}
Rotations however are strange. you should review that part of code.
Use the UIViewController rotation methods
(void)willRotateToInterfaceOrientation:duration:
(void)didRotateFromInterfaceOrientation:
instead of -(void)deviceDidRotate:
Much simpler, you will avoid that strange bouncing, and you don't need notifications any more.
Do some reading on the apple documentation on the methods i specified above.
Hope this helps.
OK, I found the error. It's pretty simple and stupid: I mixed frame and bounds.
In the displayView: code I was setting the frame of the child view to the frame of the parent view, when it should be the bounds of the parent.