Custom UIViewController is not responsive to device rotation - iphone

I have a custom UIViewController, which is the only subView of UIView. The UIViewController contains delegate function:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
This function is called once when the application starts and is never called again when the device is rotated. I also notice that the willRotateToInterfaceOrientation function is never called. I pretty much commented out all the content in the UIViewController but it is still not responding to device rotation.

I ended up solving my own problem by starting from stretch to create a brand new UIViewController and made sure it was responsive to the device rotation. I then brought in my code piece by piece and checked the rotation. In the end, I found the root cause. In my custom UIViewController, I had
- (id)initWithFrame:(CGRect)theframe {
if (self.view = [super.view initWithFrame:theframe])
It worked find excpet it did not respond to device roation even though I did not call the init function. The solution is simple. Add [self init] in the initWithFrame function. Thank you all for responding.

Your code looks correct. I suspect it's something in your .xib file (like the wrong object type for "File's Owner"), so that perhaps your view controller subclass isn't being instantiated at all. Put some logging into viewDidLoad and make sure it's getting called.

Try doing a test app that just tests the rotation problem. This will help isolate your issue.

You may need to implement that method in the controller of the parent UIView, as it seems your view is enclosed in another view.

Related

custom UIWindow orientation

I needed to see touch events on my window, so I subclassed UIWindow to make my a MYWindow class. I am overriding the sentEvent function to receive the touch events on the window and all of that is working just fine. I did the following to achieve this:
self.window = [[MYWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[window makeKeyAndVisible];
The issue I am facing is that when I do this, the viewControllers that are on this window won't rotate anymore. If I were to use a regular UIWindow, they all work just like I intended them to work. Obviously, something is wrong with my setup.
I was looking through UIWindow header file and there is a method called
- (void)becomeKeyWindow; //override point for subclass, Do Not call directly
Am I suppose to implement this in my custom UIWindow class just like I had to implement the sendEvent: method? Please point me in the right direction with this.
Thanks in advance guys.
I figured out what the issue was. I was creating a delegate on the custom window and called it "delegate" which was causing the issue. Naming it to "aDelegate" solved the issue. thanks for all your help.
I'm only guessing here, but I'd presume it is because you made MYWindow the key window now (even if it is transparent) and shouldAutorotateToInterfaceOrientation: is part of UIViewController class, not UIWindow.
So even though you can see your other views, they are not getting their rotation events called on them anymore.
Instead of making it a UIWindow subclass, why not implement those touch events on a UIView that gets added to your view that needs the touch events handled? You can make it transparent as well, and just keep the rotation handled at the UIViewController level?

shouldAutorotateToInterfaceOrientation & UINavigationController

I'm trying to implement auto-rotation in my application that is basically UINavigationController with lots of UIViewControllers that get pushed onto it.
I've copy-pasted this in my first UIViewController (that gets pushed into UINavigationController):
- (BOOL)shouldAutorotateToInterfaceOrientation:
(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
Everything worked fine... However, if I paste in that code into second UIViewController (that first one pushes on top after some button click) - autorotation won't work. shouldAutorotateToInterfaceOrientation gets called when UIViewController is first initialized, but after it is visible and I rotate device - nothing happens.
So result is: first view gets rotated well - portrait/landscape... but after I click button and get into second view I remain stuck into that portrait or landscape, whatever was active.
I tried subclassing UINavigationController and setting shouldAutorotateToInterfaceOrientation there, but that also doesn't work.
What am I doing wrong?
There's a bug in the API that doesn't cause it to work for the second view. I solved it originally using setOrientation, but that's a private API and thus not a reasonable solution. I haven't released any new versions of the application while I try to figure out alternatives (and I don't think having customers upgrade to OS 4.0 is a solution). I'm thinking I'll need to manually keep track of the orientation and rotate my views manually to counteract the effects of the wrong rotation.
You need to implement this method in all views in the hierarchy

willRotateToInterfaceOrientation not being called

I'm returning YES in my view controller's shouldAutorotateToInterfaceOrientation function, and I can see using breakpoints that YES is being returned, however the willRotateToInterfaceOrientation method isn't being called, and nor is any other rotating method. It seems like after returning YES nothing happens!
Any ideas?
Mike
Is this views viewController a subview of some other root view controller thats not a navigation controller? if so then the call does not propagate to the subviews controller, so that might be why your view isnt rotating.
I have a similar problem and saw Daniel's answer however I can't find any confirmation of this in the developer documentation. Not that I don't believe the answer but I don't really understand why the orientation call does not propagate.
Someone gave me a trick that works using something like this:
[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(detectOrientation) name:#"UIDeviceOrientationDidChangeNotification" object:nil];
One thing to look for is I found if I had UIPopoverController called in [UINavigationController viewDidAppear], then willRotateToInterfaceOrientation and didRotateFromInterfaceOrientation are not called. It looks like UIPopoverController being modal blocks the rotation method calls.
Yes me too. Ok, it won't get called in a sub-viewcontroller - have to pass it down. Can deal with that. And the notification idea works well except that you only get "did..." not "will..." (afaik) and anyway it's a messy solution to a problem which shouldn't be there.
My mistake was to call [super loadView] in my loadView. Not supposed to do that. When I removed [super loadView] and alloc'd the view myself willRotateToInterfaceOrientation started working.
What's really weird is that the [super loadView] was in the sub-viewcontroller and the event wasn't even reaching the top one...
If you are not receiving callbacks on willAutoRotateToInterfaceOrientation in any view controller, add the view controller as your root view controller's child view controller.
For Eg; say self.viewController is your root view controller and childViewController is the view controller in which you want to get auto-rotation callbacks, add the following line of code;
[self.viewController addChildViewController:childViewController];
Actually, adding as the child view controller to any view controller which gets rotation call backs will work too.
Hope it helps.
Apple documentation
At launch time, apps should always set up their interface in a portrait orientation. After the application:didFinishLaunchingWithOptions: method returns, the app uses the view controller rotation mechanism described above to rotate the views to the appropriate orientation prior to showing the window.
So if you are using a TabBarViewController be carefull to set up the selected view in the application:didFinishLaunchingWithOptions: method.

How to detect when a UIView has changed size?

I have a UIViewController that is initialised with a correct frame, however somewhere in my code the frame gets mangled and I'm having difficulty finding out where.
In situations like this it is usually handy to watch a variable in the debugger, however I have no way of accessing the controller->view->frame property in my variable view, since it isn't a variable, it's a property (surprisingly enough)
Drilling into the UIView in the variables display shows a few things but nothing I can relate to the frame, I thought perhaps that would be in layer but it isn't.
Is there any way to watch for changes in a private API? I guess not, since the variables are essentially 'hidden' and so you can't specify exactly what to watch.
Alternatively, what other approach could I use? I already tried subclassing UIView, setting my UIViewController's view to point to this subclass and breaking on the setFrame method but it didn't seem to work.
EDIT: the subclassing UIView method DID work, I just had to set the view to point to my test subclass in viewDidLoad and not the init method. Leaving this question open as I'm not sure if this is the best way of approaching this kind of problem...
Subclass your the view you want to track and rewrite the setFrame method:
#implementation MyTableView
- (void)setFrame:(CGRect)frame;
{
NSLog(#"%#", frame);
[super setFrame:frame];
}
#end
Then use the debugger to add a breakpoint to it and check when it gets called. Eventually, you'll see when the frame gets changed and where does the change comes from.
I discovered this can be done using key value observers.
http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/KeyValueObserving/KeyValueObserving.html
You could create an ivar, view2, and just assigned it to your view in your loadView method. That should enable you to watch it like a normal variable.

UIViewController not receiving touchesBegan message

I have a pretty simple UIViewController. It's initialized with a view I've created in Interaface Builder, which contains only a UIImageView. When the user touches the screen, I want the touchesBegan message of UIViewController to get called. So, I override it and added some logging, but nothing has happened.
I haven't done anything "special" at all, as since UIViewController inherits from UIResponder, I expect this to work right out of the box. From what I understand UIImageViews have user interaction disabled by default, so I have enabled it, both via InterfaceBuilder and in my UIViewcontroller's viewDidLoad method (I have tied the UIImageView to an IBOutlet). I also am ensuring that userInteraction is enabled in the parent view in Interface Builder.
Anything else that I am forgetting here?
OK, I'm a dummy. It works fine. The problem was, I didn't realize I was sending a release message to the UIViewController without having retained it elsewhere first. So that was causing the problem.
It is hard to say what your problem is, I don't know what you mean by overriding it?
Make sure you are connecting the touchesBegan event with an IBAction in Interface Builder?
You must create a IBAction function to handle the event, and explicitly connect the even to the IBAction. It is not as simple as simply overriding a method.
Although you have the View tied to an IBOutlet, you need to connect the event using an IBAction, or else you won't get any of those events.
Please ignore the first answer. It is, in fact, as easy as overriding the method in the custom view. The most common reason for not receiving touchesBegan is the canBecomeFirstResponder method not being implemented. This is not an IB hookup, these are the standard methods for touch handling.