I have UIViewController that acts like container for several other viewcontrollers. Each of that sub-viewControllers is added as a child, and only one can be visible at the moment. The problem is: when I rotate the device, container viewController handles rotation properly, as well as currently displayed child view controller. Off screen view controllers are resized properly as well, but don't receive any messages and I don't know when I should update it's contents. Is there any method of handling this, or should I instead do this all manually, e.g. storing last orientation for each viewcontroller, checking in viewWillAppear: if orientation has changed and do update manually if nescessary?
You have to check [UIApplication sharedApplication].statusBarOrientation in viewWillAppear: and adjust your views appropriately.
Also you can send orientation change message to child viewControllers, as explained here.
Related
I have an UIWebView that might show a YouTube video, so when it happens it goes full screen. My app doesn't rotates, but the UIWebView rotates, so if i stop watching it in landscape mode, when i return to my screen it goes berserk.
How can i listen for when the user taps done or to directly avoid the UIWebView to rotate?
Thanks!
We regularly have portrait-only apps that show landscape videos via web views.
Are you sure you're returning NO for landscape orientations from your shouldAutorotateToOrientation: method of the top view controller? When you say "goes berserk," what do you mean? One thing I've found is that setting the main window's rootViewController property (rather than just adding your root view controller's view as a subview of the window view) can cause trouble when returning from videos like this.
I know I'm a few months late, but I've written a simple UINavigationController subclass to properly pass the shouldAutorotateToInterfaceOrientation, willRotateToInterfaceOrientation, and didRotateFromInterfaceOrientation calls through to the proper view controller.
Hope this helps :)
https://gist.github.com/bbae6291c4f6bf05d1eb
The method viewWillAppear: in your UIViewController will be called when the video is closed from full screen. You can adjust the view there by calling setNeedsDisplay on your UIView
Alright, I am not entirely sure if I will explain this sufficiently, but here it goes.
In my application I have multiple viewControllers, that are added and removed to display different views, so on and so forth. Some of these controllers, I want to allow to rotate while other I only want in say portrait mode.
However, when I go and change the shouldAutorotateToInterfaceOrientation to return YES for a desired orientation, or even just always return YES, nothing happens when I rotate the device in some of the views.
The first view that I add to the application will rotate properly and does what I want it to do, but any subsequent view that I add to the window, just does not want to rotate as desired.
I set my parentview (main UIWindow), to autoresizeSubViews, and still nothing.
Any suggestions?
I found my problem with this was simply how I was implementing my transitions and adding new views to the screen. Before I was just taking a viewcontroller viewcontroller, and adding it as a subview to the main view, so the only thing that could control the rotation was that main viewcontroller. I did not know about the [self.navigationcontroller pushviewcontroller] thing existed. So yeah, that is what I use now and it does exactly what I need it to do.
The view, you want to allow rotation, you need implement shouldAutorotateToInterfaceOrientation with return YES; for every view! That should work, however, if you don't want to allow landscape mode, then can return NO; for landscape mode. (Default mode is portrait).
I have an application with 8 UIViewControllers presented by navigating from left/right/up/down. They are created on start of the app and kept in an NSArray. Only 1 of them is added to the view tree (addSubview:) at any time - the rest just sit in the cache until they are needed.
Now the problem I am having is when rotating to Landscape. Only the currently visible view changes the bounds.size to Landscape. When navigating to the next view, that view still thinks it is in Portrait (but the containing views will all look in Landscape).
By the way, the view hierarchy of the app is the following: UIWindow -> Main UIViewController -> 1 of the 8 cached UIViewControllers.
For example:
* Change orientation:
- Main UIViewController.view.bounds.size = 480x300 (OK)
- One of the cached UIViewControllers view.bounds.size = 480x300 (OK)
* Go to next view:
- Main UIViewController.view.bounds.size = 480x300 (OK),
- Another of the cached UIViewControllers view.bounds.size = 320x460 (??)
Not sure whats going on. Do I have to tell the cached UIViewControllers somehow that the orientation/size changed or something else?
Thanks a lot
Yes you can. Optimally you should purge the view that each view controller manages when it goes off screen.
Simply assign nil to the view property of the view controller that is being replaced. This will free all resourced used by the view that is not visible anyway. As an added bonus the view is then recreated with proper frame whenever you decide to brin a particular viw controller in front again.
I am also assuming that what you are implementing is a subclass of UIViewController that acts as a container for other view controllers. Like a sibling to UITabController named CWGridController or similar. Noe that it is the responsibility of the the parent view controller (your subclass) to size the frame of it's child view controllers views as needed.
Creating a container view controller is not a small task, and the support for doing it is not complete from Apple. There are a few things you must do including but not limited to:
Forward all orientation change calls to all child view controllers.
Properly call all appear/disappear on child view controller as needed.
The last part to make it work is to break some rules. View controllers works very badly unless they know about their parent view controller, layout will be wrong and modal view controller behaves strange. Unfortunately the parentViewController is readonly, or so you would think. Setting it anyway using KVC will solve most problems, and Apple does not seem to object when you submit to App Store:
[childViewController setValue:self forKey:#"parentViewController"];
In viewWillAppear you will have to check the interface orientation and set the frames accordingly.
My app has a welcome screen that can only be shown in portrait mode. After the user has tapped through the welcome screen I'd like to show another screen that can be used in both portrait mode and landscape.
I have set up a view controller that implements shouldAutorotateToInterfaceOrientation: returning YES only for UIInterfaceOrientationPortrait, and I add the view to the window with [window addSubView:view]. I tag this view with the tag 1.
When the user taps through the welcome view and the app moves on to the new view I do:
[[window viewWithTag:1] removeFromSuperView];
[window addSubView:myViewController.view];
Where myViewController is an instance of the 2nd view's view controller (that handles the shouldAutorotateToInterfceOrientation method properly).
Now when I rotate, it still calls shouldAutorotateToInterfceOrientation on the original view's view controller, and does not call it on the new view's view controller.
This note from Apple says that only one view controller will get rotation notifications; however, I have removed the other view controller.
What am I doing wrong?
actually that note doesn't say that "only one view controller will get the notifications" but instead it says that "Only the first view controller added to UIWindow will rotate.".
So this might be the problem.
To resolve it, i would say to always have a view added to your window (call it permanent), and add your welcome screen and the next views to this permanent view.
Hope this helps.
as the note you link to state:
Only the first view controller added
to UIWindow will rotate.
So put a flag that makes sure that shouldAutorotateToInterfceOrientation returns NO until the user have dismissed the screen - and then returns YES afterwards. This is a simple and working solution - however, from a code readability point it might be confusing that a "dismissed" view actually controll the rotation.
Personally; my experience is that it's not really worthwhile having some views rotating and some don't - and users tend to don't like it.
happy coding
I wrote up a quick test that shows what you are trying to do should work. Here are the basics I did:
Create two view controllers. App starts with the first view controller being set in the AppDelegate into an instance variable viewController through NIB files. It is then added to the window as you have written.
I then setup an action that when called (could be a Timer, button on first view controller, etc.) that performed the following:
Remove view using [self.viewController removeFromSuperview]. This is different than the way you have done with the tag.
Created second view controller and assigned it to self.viewController.
Added to window like you have specified.
Not sure what is incorrect with your code. I would guess that perhaps the first view wasn't really being removed.
My app has 4 tabs. All the view controllers support rotation, and indeed are rotated when I rotate the device. For one of the view controllers, I need to reposition some of the subviews upon rotation. I do this in willRotateToInterfaceOrientation of that view controller, and it works fine.
The problem comes when I switch to a different tab, then rotate the device, then go back to the original tab. It apparently has not received the rotation notification, since willRotateToInterfaceOrientation has not been called. So it seems as though only the "active" view controller gets notified that the device has rotated.
The question: how do you get all the view controllers (controlled by a TabBarController) to rotate?
Unfortunately this is a bug in iOS 3.x. It works fine in iOS 4.x. I've seen apps that manually keep track of orientation changes and then do the rotation manually for inactive viewcontrollers. Sucks.
Looking through the iOS 3.2 docs to make sure this works, there is a viewControllers property in UITabBarController. Try something like this:
for (UIViewController * viewController in tabBarController) {
// Do stuff here with each 'viewController'.
}
I recommend that you do something with the UIViewController's -shouldAutorotateToInterfaceOrientation: method but you may have another way in which you plan on achieving the rotation.
You should also check for the interface orientation in viewWillAppear method of the controller whose subviews frame you are changing.Because when you move to the new tab and rotate the device and now when you tap another tab the viewWillAppear method will we called and there you can change the frames accordingly.
I also faced the same problem which i sorted out using this approach