Hide an UITabBar when Orientation change - iphone

I have a quite simple question but the answer is not so easy.
I want to hide a UITabBar when my orientation change.
I looked 2 ways :
Frame way
myAppDelegate.tabBarController.tabBar.frame = CGRectMake(<<bottomOfScreen>>);
Works fine but I have a blank area, so tried to play with tabBarController.view.frame et myViewController.view.frame but I didn't get any good result.
Navigation Controller Way
myOtherVC.hideTabBarWhenPushed = YES;
[self.navigationController pushViewController:myOtherVC animated:NO];
Works but isn't a good solution for my app
Update:
[appDelegate.tabBarController.view removeFromSuperview];
[self.view removeFromSuperview]; [appDelegate.window addSubview:self.view];
self.view.frame = CGRectMake(0,0,480,320);
Works fine but doesn't autorotate anymore (and of course, I didn't change the shouldAutorotate and it always returns YES)
How can I hidde my tabBar and make the current view taking its space ?
Thanks

You can use the current solution combined with:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didRotate:) name:#"UIDeviceOrientationDidChangeNotification" object:nil];
to detect rotation. (I think that you combine this with view.transform = CGAffineTransformMakeRotation to make it rotate...?)

Two ways I think you can easily do this would be:
to reload the objects back into the tabBar controller - with the hidesBottomBarWhenPushed set to YES for the viewControllers you want to be hidden.
The other option would be to just make your view the only view for the window when the phone is rotated and then put the tabBarController.view back in the window when the phone is rotated back
Hope this helps

Related

View sizing after playing movie in fullscreen mode

I have a fairly standard navigation-based iPhone app I'm developing, where on some screens, there is a button that will play a movie using an MPMoviePlayerController in fullscreen mode. There is a navigation bar at the top of the view. I'm seeing some odd behaviour with the view sizing after the movie plays. Was wondering if anybody else has seen this, and whether there is a fix. Here is what I'm seeing:
I hold the phone in one orientation (portrait or landscape)
I start the movie (it plays in fullscreen mode)
I tap the screen to hide the movie playback controls
I rotate the phone to another orientation (portrait to landscape, or vice-versa)
I tap the screen to bring back playback controls, and then tap the 'Done' button
At this point, the original view comes back on screen, in the new orientation. However, the view is not sized properly to accomodate the status bar at the top of the screen. The status bar obscures part of the navigation bar. Rotating the phone at this point corrects the problem.
If I follow the same sequence, but without hiding the playback controls, everything works just fine, and the original view is sized properly when I dismiss the movie.
Anybody have any clue what might be causing this?
Also, this seems to be pretty easy to reproduce. I'm using Xcode4.2 and the 5.0 SDK. If you create a new iPhone-only project using the "Master-Detail Application" template, and make these changes, you can see the problem happen:
First, add the following code to MasterViewController.m.
- (void) moviePlayBackDidFinish:(NSNotification*)notification
{
MPMoviePlayerController *moviePlayer = [notification object];
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerPlaybackDidFinishNotification object:moviePlayer];
[moviePlayer.view removeFromSuperview];
[moviePlayer release];
}
- (void) playStory
{
NSURL *movieURL = [NSURL URLWithString:#"http://double-apps.com/thisisatest.m4v"];
MPMoviePlayerController *moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:movieURL];
// Register to receive a notification when the movie has finished playing.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(moviePlayBackDidFinish:) name:MPMoviePlayerPlaybackDidFinishNotification object:moviePlayer];
moviePlayer.shouldAutoplay = YES;
[self.view addSubview:moviePlayer.view];
[moviePlayer setFullscreen:YES animated:YES];
}
Then, replace the contents of the didSelectRowAtIndexPath method with [self playStory]:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self playStory];
}
That's it, run the app, hit the 'Detail' entry in the main screen, then follow the sequence listed above.

UIView addsubview after orientation change: Tell view to resize

I have a UIView as a XIB in Portrait mode.
This view is added programmatically to the viewcontroller like this:
NSArray *nibObjects = [[NSBundle mainBundle] loadNibNamed:#"InputView" owner:self options:nil];
InputView *inputView = (InputView*)[nibObjects objectAtIndex:0];
[self.view addSubview:inputView];
This view has autoresizing masks set up properly and rotates fine when the orientation changes from Portrait to landscape.
However, if the orientation is already landscape and I create the view after the orientation change, it has its initial portrait orientation.
Is there a way to tell the view to initialize or resize itself to portrait by using its masks?
Thanks in advance for any reply!
EDIT:
Using the suggestions of occulus and Inder Kumar Rathore (thanks guys!), I altered the code to this:
InputView *inputView = (InputView*)[nibObjects objectAtIndex:0];
[self.view addSubview:inputView];
[self.view setNeedsLayout];
[self.view layoutSubviews];
[self.view layoutIfNeeded];
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
[self shouldAutorotateToInterfaceOrientation:orientation];
Unfortunately, there is no change at all.
I think I found someone asking the same question:
When adding a sub view the view does not resize if the app is in landscape mode
The answer identifies the problem correctly, but is not very encouraging...
Sure, I could create two nibs or resize the frame, but this seems so contrary to the idea of auto-resizing.
I find it hard to believe that there is no way to tell a nib after awakening and adding it to a view to use its autoresize features...something that works flawless when the device rotates.
EDIT 2:
The solution of idz works:
InputView *inputView = (InputView*)[nibObjects objectAtIndex:0];
[self.view addSubview:inputView];
inputView.frame = self.view.bounds;
[inputView show];
Thanks!
Often a NIB/XIB file contains a UIViewController that takes care of all of this. In this case, since their is no view controller (in the NIB/XIB) you need to take over its post-load duties.
Calling layoutSubviews directly, or indirectly via setNeedsLayout or layoutIfNeeded won't do you much good because the default implementation does nothing.
Assuming you want input view to fill the bounds of self.view you do the following:
InputView *inputView = (InputView*)[nibObjects objectAtIndex:0];
[self.view addSubview:inputView];
inputView.frame = self.view.bounds;
[inputView show];
All the resize masks of the sub-views must be correctly set for this to work and, obviously, if you don't want to fill the full bounds you may want to adjust the frame.
[self.view addSubview:viewSpinner];
viewSpinner.frame = self.view.frame;
[viewSpinner setNeedsLayout];
This works for me (Y)
I don't know if you still have this issue.
Let's say you have the following architecture:
window
subviewcontroller
(you implemented shouldautorotate correct to answering the wanted orientations)
Into this subviewcontroller you want to add the views of new UIViewControllers by just calling the addSubview function.
Instead of implementing the bounds manipulation in shouldautorotate, you should implement it in
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation{
self.newUIViewController.view.frame = self.view.bounds;
}
didRotateFromInterface... is called after shouldRotate. In this function the bounds are already setup correctly.
This way you don't need so much manipulation by code.
See this related question:
When do autoresizing masks take effect in iOS?
So after loading your new view from the nib, and adding as a subview to self.view, try calling setNeedsLayout.

iphone: rotation in mpmovieplayercontroller?

I have a small view on top of an mpmovieplayercontroller. When it is not fullscreen, I am able to adjust the frame of the view to the orientation (when the device rotates). But when I enter fullscreen mode, alothough I manage to present the view, I'm no longer able to maintain the correct frame when the device rotates. It looks like in fullscreen mode, the system simply using CGAffineTransformRotate on the status bar and the moviePlayer. How can I apply this CGAffineTransformRotate to rotate my view correctly?
EDIT:
Ok, so I updated the code to rotate 90% in the X axis after a change in orientation of the mpmovieplayercontroller but the view simply disappears after the first rotate. Here is my code:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
float angle = M_PI / 2; //rotate 180°, or 1 π radians
theView.layer.transform = CATransform3DMakeRotation(angle, 1.0, 0.0, 0.0);
[self changePositionBasedOnOrientation:toInterfaceOrientation]; //here we change the frame of the view
}
I'm not sure if this would necessarily be the correct way to do it (I guess you're adding a subview to the MPMoviePlayerController view?), but what you seem to be after is a callback to when the movie player rotates in fullscreen so you can adjust your own custom views.
You could register for rotation notifications on your custom view, which can then adjust itself every time it receives a callback. You register for rotation notifications as follows:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(layoutViewForOrientation:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
You should remember to endGeneratingDeviceOrientationNotifications and remove your notification observer when you're done with the fullscreen mode.
Ok,
So the best way to overlay the mpmovieplayercontroller in fullscreen is to it like that:
[[[[[UIApplication sharedApplication] keyWindow] subviews] objectAtIndex:0] addSubview:mySubview]
It's a bit hacky, but legitimate. It gives you an easy way to deal with rotations (instead of using transformations).

Only first UIView added view addSubview shows correct orientation

I've got three ViewControllers set up to handle three views. The problem that I'm having is that in the simulator the orientation is LandscapeRight (which is what I want), and the first view shows up correctly in that landscape view, but when I move onto the second and third views, they show up rotated 90 degrees counter-clockwise with the upper-left corner of the view in the lower left corner of the phone's screen. I've been trying to debug this for a few days and the closest that I've gotten to a clue is tracing it the following way:
The following is in my app delegate's applicationDidFinishLaunching:
NSLog(#"1");
[window addSubview:welcomeController.view];
NSLog(#"2");
[window addSubview:goalController.view];
NSLog(#"3");
[window addSubview:planningController.view];
NSLog(#"4");
[window bringSubviewToFront:welcomeController.view];
NSLog(#"5");
Each of my ViewControllers implement something similar to the following (the only change being the controller's name switched out in the string passed to NSLog):
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
NSLog(#"called for WelcomeController");
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
With that, I get the following output on the Console:
a
called for WelcomeController
called for WelcomeController
called for WelcomeController
called for WelcomeController
2
called for GoalController
3
called for PlanningController
4
5
I find it interesting that shouldAutorotateToInterfaceOrientation is called 4 times for the first view that's added, while the other two only get called once. I expect that this is probably because it's got to do some setup at first (and I believe that the simulator starts off in portrait mode, so it's might be calling it while doing the rotation), but I find the correlation a bit suspicious.
I've switched the order around so that the addSubview is called for the goalController first and the welcomeController second. In this case, it's the goalController which displays in the correct landscape orientation (it's normally the welcome controller). This would seem to eliminate my XIB files and the ViewControllers themselves. I'm not sure why the first view where addSubview is called is special. I also tried using insertSubview at index 0 with the same results.
Ran into the same problem, and apparently adding subviews to a UIWindow doesn't work the way I expected it to. I managed to solve the problem after adding a "dummy" UIViewController that is the ONLY subview in the UIWindow. After adding that one, it works perfectly to add multiple subviews to the dummy-controller, all with the correct orientation.
So the only code in the "dummy" controller class is the "shouldAutorotateToInterfaceOrientation" function. This should also match the same function in all the other subviews.
Hope it helps.
I had a similar issue. Not sure why either. But the workaround was to call this on every view after the first one:
[planningController.view setFrame:CGRectMake(0, 0, 480, 300)];
and before -addView. I'm curious if this helps you out. If I am not the only one with this problem and this workaround, then maybe there's a reason.
This is far far far from ideal. But you can hack the second views transform so it is rotated correctly. This works for me because my app is only ever in landscape mode. It may not be ideal if you want to change orientation.
[window addSubview:firstController.view];
[window addSubview:secondController.view];
CGAffineTransform rotate = CGAffineTransformMakeRotation(M_PI/2.0);
[backgroundViewController.view setTransform:rotate];
CGRect contentRect = CGRectMake(0, 0, 1024, 768);
backgroundViewController.view.bounds = contentRect;
[backgroundViewController.view setCenter:CGPointMake(768/2, 1024/2)];
I think I have a solution for this that appears to work. Add a view, and then immediate remove it, repeat for each view, then add all three. Like this:
[window addSubview:welcomeController.view];
[welcomeController.view removeFromSuperview];
[window addSubview:goalController.view];
[goalController.view removeFromSuperview];
[window addSubview:planningController.view];
[planningController.view removeFromSuperview];
[window addSubview:welcomeController.view];
[window addSubview:goalController.view];
[window addSubview:planningController.view];
It seems to work, at least in the simulator.

Change view layout with orientation

I am working on an application where I want the view to change quite a lot when the device is rotated. I know that in Interface Builder it is possible to change the orientation and set up the layout there, however when I then rotate it to portrait, the view is the same as for the landscape. Is there a way to set up the two views independently, perhaps using two nibs?
Cheers,
JP
If you're after switching view controllers on orientation changes, like when the iPod app shows it's coverflow view, the following post will help:
http://rndnext.blogspot.com/2009_06_01_archive.html
I don't know if you can do it in IB, but I know you can do it in code. You need to observe the UIDeviceOrientationDidChangeNotification Notification:
(in viewDidLoad...)
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(updateViewOnRotate:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
....
-(void) updateViewOnRotate:(NSNotification *notification) {
// update the views
}