I have an iPad app that is set to start in landscape mode.
From what I read, the UIWindow itself doesn't need to be rotated, instead it will apply a rotation transform to all of it's subviews when the device is rotated.
My application has a UINavigationController which has the app's views, and above it a custom MenuBarViewController which will show sometimes on one edge of the screen.
In my app delegate's didFinishLaunching.. I do:
[window addSubview:navigationController.view];
[window addSubview:menuBarWrapperViewController.view];
[window bringSubviewToFront:menuBarWrapperViewController.view];
The views within my navigationController seem to be fine, however the view in my MenuBarViewController are not rotated.
I've checked, and both my MenuBarViewController and my MenuBarWrapperViewController (which doesn't do anything yet) return YES to shouldAutorotate..
Does anyone have any idea why one of my UIViews subviews doesn't get the correct rotation transform?
EDIT: upon further investigation, it seems that UIWindow only applies the transform to the first added subview, so if I change the order of addSubview calls, only the first subview will be rotated.
Does anyone know why?
Perhaps you should try having one view controller be in charge of handling all rotations of all subviews being displayed.
Related
I have my UIWindow structured in Interface Builder as:
window
drawingView (custom UIView)
toolbar (UIToolbar)
Where the drawingView handles touches using touchesBegan etc. However, when I try and add 'someView' (a custom UIView) which has UIButtons on it as a subview of window, the buttons don't receive any of the touches.
I create 'someView' with:
[[[UIApplication sharedApplication] keyWindow] addSubview:someView];
'someView' displays fine on top of the drawingView, but the touches don't seem to register at all, and get passed through to drawingView. Why is that?
Another odd thing is that the backgroundColor of someView always seems to be clear, even if I set it to something else programatically or in IB.
Also, when I create someView using
[[UIPopoverController alloc] initWithContentViewController:someView];
it works fine, handling touches and all. The reason I want to add it as a subview is because I want a more general way of adding someView, that is works on the iphone as well.
Make sure the userInteractionEnabled flag is set on all parents of the view that needs to receive touches.
I've figured out a fix (in a hackish kind of way).
I had to add 'someView' as a subview of drawingView, which appears on top of drawView when shown, and allows me to programatically set up someView with UIButtons, which receives touches.
I think it's because drawView is an OpenGL view, that overrides layerClass which does something funky with how the views are arranged to obtain touches. I think.
In my iPhone app, I have a UIViewController with two subviews: a main UIView (let's call it mainView), and a secondary UIView (let's call it secondView), which is usually hidden but is sometimes shown (e.g. user settings). In my UIViewController, self.view is set to mainView. When the user switches to the subview, I call [self.view addSubview:secondView] and when the user switches back to the main UIView, I call [secondView removeFromSuperview].
There are two issues which I am dealing with at present:
When the user rotates the iPhone or iPad, the main UIView (mainView) autorotates properly and all of its UI items follow its autoresize rules which I have set up in Interface Builder. However, when the secondary UIView (secondView) is displayed, and the iPhone or iPad is rotated, the secondView & all of its UI items do not follow their autoresize rules. I have found that when I set self.view = secondView, and then rotate the device, the view rotates properly.
In the iPad specifically, when I pull up the secondView using [self.view addSubview:secondView], it is not resized to fill the full screen just as the main UIView has been resized for the iPad version. So I end up with a screen that displays the mainView UIView in the background, and the secondView UIView in the top-left corner without taking up the whole screen.
My instinct tells me that these two issues are related to one another. Has anyone else experienced these kinds of issues with secondary UIViews which they add to their UIViewControllers using addSubview:?
When using addSubview,
[secondView setFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];
Not very elegant. But it worked for me:
I had a similar problem. I solved the size issue by setting the content mode of the view.
Exp:[_yourView setContentMode:UIViewContentModeScaleAspectFill];
I hope this helps...
In my iPhone app, I have a view controller with two views (essentially, a front & back view). The front view is the main UIView, and the back view is a secondary UIView which is added as a subview using [self.view addSubview:backView] when showing the back and [backView removeFromSuperview] when hiding it. However, when the orientation changes, I have the following issue: the main UIView (frontView) rotates & all of its elements resize properly, but the secondary/subview UIView (backView) does not rotate & all of its elements do not resize properly. Does anyone have suggestions on how to make the secondary UIView autoresize properly according to the rules I have set in Interface Builder?
In the end, the solution I found was simply to separate my UIViews into separate UIViewControllers, and make sure that any views that I wanted to be able to rotate only had one UIView.
If I understand correctly, at the time of rotation 'backView' has been removed from it's superview, yeah? If so, that's the cause of the problem. The autoresize property determines how the view resizes relative to it's superview. If it doesn't have a superview it won't resize.
Perhaps using [backView setHidden:YES] instead of [backView removeFromSuperview] will be sufficient for your needs.
I had the same problem, here is how I fixed it based on imaginaryboy's
suggestions (thanks!)
Add the backview to the viewcontroller at viewDidLoad and hide it at the same time. Show it when needed, Hide it again. Set the resizing of the backview to UIViewAutoresizingFlexibleWidth in IB (or code I guess, I used IB)
Not that this is the same problem, but I found a similar problem when adding 2 subviews in my application:didFinishLaunchingWithOptions method. Since your reference above is using [self.view addSubview:view], I would understand that to mean that self is not your UIWindow. When adding an additional view controller to your App Delegate window (UIWindow), the second view controller will NOT receive any rotation events and will never rotate. Only the first view controller added to UIWindow will rotate. See:Technical Q&A QA1688 I believe this also affects views added after the first view where the first view is later removed from the superview.
I ended up following the suggestion I read elsewhere to use separate views for each orientation, thereby eliminating the need to worry about resizing behavior. As always, YMMV.
Or; if you want to avoid an additional controller, you can achieve the same effect by setting view.frame in willRotateToInterfaceOrientation:: like so
if(UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation])) ;//set stubborn view.frame for landscape orientation
else ; //set stubborn view.frame for portrait orientation
Although it feels like a hack; it's simple.
I have a view based app. Its self.view has several subviews and shouldAutorotateToInterfaceOrientation is returning YES.
When I rotate the device, all views rotate as expected.
Is that possible to prevent a subview from auto rotating even if the view's parent is auto rotating?
Keep in mind that it's the view controller that controls what happens during rotation and not the view itself. You can't stop a subview from rotating by setting a property, or something relatively easy, if its parent view's UIViewController is set to auto rotate. You can, however, have sibling views where one rotates and the other doesn't. It's probably possible to layout your views the way you want but not have the one that shouldn't rotate as a subview of a rotating UIViewController.
You could probably write some code that will reorient a subview so it appears not to rotate when the parent view does rotate, however.
I have two apps, both of which force the user to use the iPhone in landscape mode, in order to have a wider screen, instead of a taller one.
One of the things I have found is that my first view will look fine, but all other views come up with their subviews (UIButtons, UIPicker, UIViews) squeezed to one side or clipped (depending on whether the elements were set to move, resize or stay in the same position as the view size changed). All my views are designed in IB in the landscape orientation. My underlying UIWindow, and everything I can think of has been laid out in landscape orientation. Even my plist file has the UIInterfaceOrientationLandscapeRight flag set.
Now, if I load all my views at the same time as my rootview controller, then I have no problems. But if I have views loaded later, they get clipped or squeezed.
The only way to get around the problem was to add the following line in my code that flips in a new view:
[coming.view setFrame:CGRectMake(0, 0, 480, 300)];
Anyone know why I need to do this? Is it just that the iPhone assumes that loaded views are 300x480 unless a transform gets applied to them?
Thanks.
ps. This is what the view looks like if I don't call setFrame, as described above:
alt text http://files.me.com/mahboud/ljhvun
All viewcontrollers that get loaded after the first one will have their screen similarly squeezed down. For some reason the first viewcontroller doesn't have this issue.
I think you want to use landscape mode in each single view in your app. And you want the nib to be landscape mode too. You can resize the view to (0,0,480,300 for statusbar, 320 for non-statusbar) in nib. And design what you want. Finally, in view controller return no for autorotate. And finally transform the view and rotate.
I had a similar problem, asked the question on SO, and then figured it out and answered it myself. You may want to check it out.
A proper answer will depend on knowing how you are forcing landscape orientation. If you are doing this through UIViewController and company, it should be relatively simple; for other methods probably more complex.
In the simple case, you should be able to override shouldAutorotateToInterfaceOrientation: on your view controller, setup your views in Interface Builder, and set the UIInterfaceOrientation key to UIInterfaceOrientationLandscapeRight in your Info.plist and be set.
A simple way I fixed this was to have my root view controller subclass UINavigationController, and implement shouldAutorotateToInterfaceOrientation to handle landscape view ie,
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return ((interfaceOrientation == UIInterfaceOrientationLandscapeLeft) ||
(interfaceOrientation == UIInterfaceOrientationLandscapeRight));
}
Every view controller that is pushed to the navigation controller seems to appear in landscape too.