I've made an iPad application,
It works fine when I load my application in portrait mode for first time, but when I load my application in landscape mode for the first time, it takes the coordinates of portrait mode only, because inside my didLoad method I give coordinates of portrait mode only.
Now need to give coordinates of landscape mode inside my didLoad method.
I tried this, inside my didLoad method
if (interfaceOrientation == UIInterfacePortraitmode ||
interfaceOrientation == UIInterfaceUpsideDown)
{
// do this....
}
else
{
// do this....
}
but I am unable to write the condition for the if/else inside my didLoad method.
What should I do?
You can do handling as below -
-(void) viewWillAppear: (BOOL) animated {
[super viewWillAppear: animated];
[self updateLayoutForNewOrientation: self.interfaceOrientation];
}
-(void) willAnimateRotationToInterfaceOrientation: (UIInterfaceOrientation) interfaceOrientation duration: (NSTimeInterval) duration {
[self updateLayoutForNewOrientation: interfaceOrientation];
}
and then finally custom method -
- (void) updateLayoutForNewOrientation: (UIInterfaceOrientation) orientation {
if (UIInterfaceOrientationIsLandscape(orientation)) {
// Do some stuff
} else {
// Do some other stuff
}
}
-(void) viewWillAppear: (BOOL) animated {
[super viewWillAppear: animated];
[self adjustViewtForNewOrientation: self.interfaceOrientation];
}
-(void) willAnimateRotationToInterfaceOrientation: (UIInterfaceOrientation) interfaceOrientation duration: (NSTimeInterval) duration {
[self adjustViewtForNewOrientation: interfaceOrientation];
}
- (void) adjustViewtForNewOrientation: (UIInterfaceOrientation) orientation {
if (UIInterfaceOrientationIsLandscape(orientation)) {
// Do some stuff
} else {
// Do some other stuff
}
also call adjustViewtForNewOrientation in your ViewDidLaod() method,
I had similar issue with UIScrollView. I had it fixed by aligning the subviews as suggested here.
- (void)alignSubViews
{
// Position all the content views at their respective page positions
scrollView.contentSize = CGSizeMake(self.contentViews.count * scrollView.bounds.size.width,
scrollView.bounds.size.height);
NSUInteger i = 0;
for (UIView *v in self.contentViews) {
v.frame = CGRectMake(i * scrollView.bounds.size.width, 0,
scrollView.bounds.size.width, scrollView.bounds.size.height);
i++;
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
//Setup subviews and then align the views.
[self alignSubViews];
}
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
duration:(NSTimeInterval)duration
{
[self alignSubViews];
scrollView.contentOffset = CGPointMake(self.currentPage * scrollView.bounds.size.width, 0);
}
Related
I have an app which has 2 view controllers. The first viewcontroller should be in portrait and it's ok, but when I'm loading the second view controller, I could not make the app orientation to be landscape... The problem is with iOS 6.
I have tried everything I found on SO.
Using [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:NO]; on viewWillAppear and viewDidLoad,
and also:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (interfaceOrientation == UIInterfaceOrientationPortrait) {
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
} else {
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
}
-(BOOL)shouldAutorotate
{
return YES;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationLandscapeRight;
}
-(NSInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskLandscapeRight;
}
Add these code in 2nd View Controller's viewDidLoad method to transform view into landscape :
[self rotateController:self degrees:-90];
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeLeft animated:NO];
//set it according to 3.5 and 4.0 inch screen in landscape mode
[self.view setBounds:CGRectMake(0, 0, 480, 320)];
add rotateController method :
-(void) rotateController:(UIViewController *)controller degrees:(NSInteger)aDgrees
{
UIScreen *screen = [UIScreen mainScreen];
if(aDgrees>0)
controller.view.bounds = CGRectMake(0, 0, screen.bounds.size.height, screen.bounds.size.width);
else
{
controller.view.bounds = CGRectMake(0, 0, screen.bounds.size.width, screen.bounds.size.height);
}
controller.view.transform = CGAffineTransformConcat(controller.view.transform, CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(aDgrees)));
}
Now in viewWillDisappear's method to transform view into protrait . Add these:
[self rotateController:self degrees:90];
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO];
//set it according to 3.5 and 4.0 inch screen in protrait mode
[self.view setBounds:CGRectMake(0, 0, 320, 480)];
Also your orientation methods should be like these if not added add these :
- (BOOL)shouldAutorotate
{
//make view landscape on start
return NO;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscapeLeft;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationLandscapeLeft;
}
EDIT : Add these macro for radian
#define DEGREES_TO_RADIANS(angle) ((angle) / 180.0 * M_PI)
you may add this code on this view controller where you want to fix your orientation
Code as Below
-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if(UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPhone)
{
return UIInterfaceOrientationMaskPortrait;
}
}
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
if(UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPhone)
{
return (toInterfaceOrientation==UIInterfaceOrientationPortrait);
}
}
and second view controller you may want to rotate all orientation then not necessary to adding any code ios6 will manage the orientation automatically.
You need to select the landscape mode in application summary-> deployment info.
Also if you are using xib file to design the UI, you need to set the orientation of second view controller to landscape
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
-(BOOL)shouldAutorotate
{
return NO;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationLandscapeRight;
}
-(NSInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscapeRight;
}
You were not returning the NO in the method shouldAutorotate , replace you existing code with this .
Hope it will help you.
Prior to iOS 6 i.e in iOS 5 and earlier, an app and a view controller’s rotation is controlled by the individual viewcontrollers while in iOS 6 and later, the view controllers responsible for rotation are the container Viewcontrollers such as UINavigationController & UITabBarController . What are you using as the rootviewcontroller in your project??
Autorotation is clearly explained here in this post- Autorotation in iOS
In iOS6 in the methods viewControllerAfterViewController and viewControllerBeforeViewController if I return nil (for block the page navigation when I am in the first or last page) the app crash with this exception:
'The number of view controllers provided (0) doesn't match the number required (1) for the requested transition'
In iOS5 all works good.
I had the same issue. I found that the cause was replacing the delegate on the UIPanGestureRecognizer of the UIPageViewController, a no-no really. The pan gesture recognizer was calling an undocumented method _gestureRecognizerShouldBegin: (note the leading underscore) that UIPageViewController implements and apparently relies upon to work properly (read: not-crash). I ended up implementing respondsToSelector: and forwardingTargetForSelector: in my class that uses the UIPageViewController to pass the undocumented delegate method on to the UIPageViewController without specifically naming it (and almost certainly earning me an app store review rejection).
-(BOOL)respondsToSelector:(SEL)aSelector {
if ([super respondsToSelector:aSelector])
return YES;
else if ([self.pageViewController respondsToSelector:aSelector])
return YES;
else
return NO;
}
- (id)forwardingTargetForSelector:(SEL)aSelector {
if ([super respondsToSelector:aSelector]) {
return nil;
} else if ([self.pageViewController respondsToSelector:aSelector]) {
return self.pageViewController;
}
return nil;
}
My longer term solution will be to rework the use of UIPageViewController such that I don't need to displace the gesture recognizer delegates.
Ah,was wondering why no one has pointed out this bug,which i took almost 2 nights to find out the solution.
OLD CODE(iOS 5.1) : when returning nil on the first and last page you will experience the app crash.It works fine in iOS 5.1,but in iOS 6 it wont.
- (UIViewController *)pageViewController:
(UIPageViewController *)pageViewController viewControllerBeforeViewController:
(UIViewController *)viewController
{
for (UIGestureRecognizer *recognizer in pageController.gestureRecognizers) {
if ([recognizer isKindOfClass:[UITapGestureRecognizer class]]) {
recognizer.enabled = NO;
}
}
NSUInteger index = [self indexOfViewController:
(MainViewController *)viewController];
if ((index == 0) || (index == NSNotFound)) {
return nil;
}
index--;
return [self viewControllerAtIndex:index];
}
- (UIViewController *)pageViewController:
(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
for (UIGestureRecognizer *recognizer in pageController.gestureRecognizers) {
if ([recognizer isKindOfClass:[UITapGestureRecognizer class]]) {
recognizer.enabled = NO;
}
}
NSUInteger index = [self indexOfViewController:
(MainViewController *)viewController];
if (index == NSNotFound) {
return nil;
}
}
SOLUTION(iOS 6) : After adding the gesture effect to the superview,just call the delegate called -(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer. What i did is quiet simple, computing the speed of the user flipping the first page and last page (i mean using the gesture recognizer) , i denied the swiping.All you need to do is just paste the following code,and you are DONE!.
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
if (pageNum==0) {
if ([(UIPanGestureRecognizer*)gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]] &&
[(UIPanGestureRecognizer*)gestureRecognizer velocityInView:gestureRecognizer.view].x > 0.0f) {
//NSLog(#"Swiping to left on 1st page is denied");
return NO;
}
if ([(UITapGestureRecognizer*)gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]] &&
[(UITapGestureRecognizer*)gestureRecognizer locationInView:gestureRecognizer.view].x < self.view.frame.size.width/2) {
//NSLog(#"tapping to left on 1st page is denied");
return NO;
}
}
else if(pageNum ==totalNoOfFiles-1)
{
if ([(UIPanGestureRecognizer*)gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]] &&
[(UIPanGestureRecognizer*)gestureRecognizer velocityInView:gestureRecognizer.view].x < 0.0f) {
//NSLog(#"Swiping to right on 1st page is denied");
return NO;
}
if ([(UITapGestureRecognizer*)gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]] &&
[(UITapGestureRecognizer*)gestureRecognizer locationInView:gestureRecognizer.view].x > self.view.frame.size.width/2) {
//NSLog(#"Tapping to right on 1st page is denied");
return NO;
}
}
return YES;
}
- (UIViewController *)pageViewController:(UIPageViewController*) pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
int index = [self indexOfViewController:(ChildViewController *)viewController];
index--;
return [self viewControllerAtIndex:index];
}
- (UIViewController *)pageViewController:
(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
int index = [self indexOfViewController:(ChildViewController *)viewController];
index++;
return [self viewControllerAtIndex:index];
}
This has been well discussed but I have one thing to add. Consider why you were setting the delegate of the gesture recognizers to self. In my case, it was because in some cases I wanted to prevent the gesture recognizers from recognizing, with the delegate's gestureRecognizerShouldBegin:.
But in iOS 6, where this issue arises, there is a whole new way of doing exactly that, by implementing gestureRecognizerShouldBegin: on a UIView. (This is a new UIView instance method in iOS 6.)
Thus I was able to accomplish exactly what I was accomplishing before, without altering the gesture recognizers' delegate.
I had the issue with UIPageViewController crashing with iOS6 with the same error ('The number of view controllers provided (0) doesn't match the number required (1) for the requested transition').
None of the above solutions worked for me but I eventually found that moving the following line from viewDidLoad to viewDidAppear fixed it.
self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;
Totally same issue here.
What I did was a hotfix which just to returns clone of before/afterViewController instead of nil, i.e.
// viewController = before/afterViewController
NSUInteger index = [self indexOfViewController:viewController];
// NOTE: return nil crashes in iOS6
return [self viewControllerAtIndex:index storyboard:viewController.storyboard];
This means you can page-curl forever but I had no other choice...
Better solution is always welcome.
My app must NOT auto-rotate at all. But it includes a screen which tells the user to rotate his phone (and not the opposite!).
To do that, the ViewController must make an animated rotation (without any rotation event) when the screen is displaying.
So I used
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeLeft animated:animated];
}
- (void)viewWillDisappear:(BOOL)animated {
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:animated];
[super viewWillDisappear:animated];
}
And
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
return YES;
}
to make my screen rotate, as every website and documentation recommend.
But only the StatusBar rotates: my NavigationBar remains stuck at the top.
I would use a CGAffineTransform perhaps on the navigationcontroller view? Simply rotate it using an animation block 90 degrees?
this code is helpful for you to resize the navigation bar automatically you can use it in where you create the navigationController & navigation bar
self.navigationController.navigationBar.autoresizesSubviews = YES;
self.navigationController.navigationBar.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
above code will work automatically if it is not then you try this will work in all delegates methods of your view controller where you need the change
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeLeft animated:animated];
[self.navigationController shouldAutorotateToInterfaceOrientation:[UIApplication sharedApplication].statusBarOrientation];
}
- (void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
CGRect frame = self.navViewController.navigationBar.frame;
frame.size = self.view.frame.size;
if (toInterfaceOrientation == UIInterfaceOrientationPortrait || toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) {
frame.size.height = 44;
} else {
frame.size.height = 32;
}
self.navViewController.navigationBar.frame = frame;
if navigation controller is rootview controller then check it enables the all orientation supports
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
[super shouldAutorotateToInterfaceOrientation:toInterfaceOrientation];
[self.navigationController shouldAutorotateToInterfaceOrientation:toInterfaceOrientation];
return YES;
}
you can use this code in viewcontroller delegates listed below according to your requirment
- (void)viewDidAppear:(BOOL)animated
- (void)viewWillAppear:(BOOL)animated
– willRotateToInterfaceOrientation:duration:
– willAnimateRotationToInterfaceOrientation:duration:
– didRotateFromInterfaceOrientation:
What would be the correct way to achieve an effect similar to the one in the standard iPod app of the iPhone - when the device is rotated to landscape mode, the view changes to cover flow, but the type of transition is fade and not the rotating screen?
This is how I am loading the modal view:
- (void) willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
if (UIInterfaceOrientationIsLandscape(toInterfaceOrientation)) {
carouselView.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:carouselView animated:YES];
}
}
Thanks!
Andrius
I later found that it is more stable to use this solution:
In the parent view controller (in my case it is tab view controller) viewdidload method add this:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didRotate:) name:#"UIDeviceOrientationDidChangeNotification" object:nil];
and then add this method:
- (void) didRotate:(NSNotification *)notification {
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
if (UIInterfaceOrientationIsLandscape(orientation) && !self.modalViewController) {
[self presentModalViewController:carouselView animated:YES];
[Globals sharedGlobals].startedAtLandscape = YES;
}
if (UIInterfaceOrientationIsPortrait(orientation) && self.modalViewController) {
[self dismissModalViewControllerAnimated:YES];
[Globals sharedGlobals].startedAtLandscape = NO;
}
}
And finally if you want to prevent the rotation animation, modify this method like this:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if(UIInterfaceOrientationIsLandscape(interfaceOrientation)) {
return NO;
}
return YES;
}
Hey!
I have a xib file were i would like a round rect button to stay highlighted after it is pressed. I also would like to have a different button that is pressed after the first one that takes you to the next page. How can I do this. Some code would be greatly appreciated!
This is my .h:
#import <UIKit/UIKit.h>
#interface Test1ViewController : UIViewController {
IBOutlet UIButton *button1;
IBOutlet UIButton *button2;
}
-(IBAction) buttonPressed:(id)sender;
-(IBAction) secondButtonPressed:(id)sender;
- (void)flipButton;
#end
This is my .m:
#import "Test1ViewController.h"
#import "Page2.h"
#implementation Test1ViewController
-(IBAction)buttonPressed:(id)sender
{
[self performSelector:#selector(flipButton) withObject:nil afterDelay:0.0];
}
- (IBAction)secondButtonPressed {
if ( button1.selected ) {
Page2 *page2 = [[Page2 alloc] initWithNibName:#"Page2" bundle:nil];
page2.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:page2 animated:YES];
[page2 release];
}
}
/*
// The designated initializer. Override to perform setup that is required before the view is loaded.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
*/
/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
}
*/
/*
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
}
*/
/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
*/
- (void)flipButton {
if ( button1.selected ) {
button1.highlighted = NO;
button1.selected = NO;
} else {
button2.highlighted = YES;
button2.selected = YES;
}
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
}
#end
Thanks a lot for all the help!
You will have to use the highlighted property of the button to set the state as highlighted or otherwise. However doing immediately on Touch Up Inside seems to reset it. So we delay the change until the next run loop starts. Do this on the method called on touch.
-(IBAction)buttonPressed:(id)sender
{
[self performSelector:#selector(flipButton) withObject:nil afterDelay:0.0];
}
and define the flip method as follows –
- (void)flipButton {
if ( self.button.selected ) {
self.button.highlighted = NO;
self.button.selected = NO;
} else {
self.button.highlighted = YES;
self.button.selected = YES;
}
}
You can later check on the method called on tap of the other button whether self.button.selected is YES or not and then act on it.
- (IBAction)secondButtonPressed {
if ( self.button.selected ) {
// Load next page.
}
}
Better Approach
Use a UISwitch. Don't you think that it is a natural fit.