I have an app that is running in landscape and it is awfully inconvenient to keep having to transform every object that I add to the screen, isn't there some way that I can add a transform (global you might call it) to the view as a whole so that every object in the view can be placed in the coordinate system that is most convenient (ie. top left corner is zero, zero), instead of the crazy coordinate system I have to use?
I was dealing days with the same issue and I haven't found a nice way to transform coordinates. So I'm stuck with the same method as you - I transform-rotate each UI element so it appears in landscape.
The other way is if you use view controller and autorotate the whole view. But I didn't find that a convenient way to implement this. If you find a better solution please do post it here.
I add a bunch of subviews to my view to add some buttons, and trying to have the buttons rotated without having to do a transform on each one, not getting anywhere.
Ahah, i found that if you just assign the transform to a view it doesn't seem to do anything.
so myview.transform = mytransform
is a NOP
but [myview setTransform:mytransform]
does do something.
But just rotating the view from portrait to landscape screws up the coordinates,
so you need to offset by half of the difference:
// this will transform your coordinates so that you can draw kind of normally
CGAffineTransform rotate = CGAffineTransformMakeRotation(1.57079633);
rotate = CGAffineTransformTranslate (rotate, -80.0, +80.0);
[myView setTransform:rotate];
Now I can add buttons in a convenient coordinate system.
However my view background is now shifted -80, +80 pixels, because of the translation I added to the view. How can i load a background into the view without getting fouled up by my transform?
I have a view background (currently stored as landscape):
UIImageView *myviewback = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"back_spreads.png"]];
[self addSubview:myviewback];
My background gets rotated as the transform indicates, but the translation
i put in to fix the coordinates fouls up the background, how do I fix this?
The code I posted works for me. I apply it once in the VC, add the view to the subview and everything is rotated (buttons, images etc).
They even stay rotated when I run [self setNeedsDisplay];
How do you do that in in VC? You add transformed view as a subview to UIViewControler.view proeprty or you transform the view and then assign it to the UIViewControler.view proeprty?
i was setting the center point before, but now that i don't set the center point, the background image is magically getting rotated about its center, don't know why this would happen but hey the default is working okay, so things are getting better! Thanks for the help guys, this view/subview stuff is confusing, and the documentation is non-existent!
i was setting the center point before, but now that i don't set the center point, the background image is magically getting rotated about its center, don't know why this would happen but hey the default is working okay, so things are getting better! Thanks for the help guys, this view/subview stuff is confusing, and the documentation is non-existent!
Great to here. At what point are you setting this transformations? LoadView? Init? Can you post the full code?
Before i rashly stated my program was working in landscape properly. It is drawing okay, but not responding to touches properly because the area for responding to touches is only extending on the left side of the landscape screen (magically only 320 pixels across), and any touches on the right side are not getting tracked.
so after setting the view transform, one must do something else, probably the fame, but not sure how to fix it. Anyway have a few lines of code they can share to fix the frame after applying the 90 degree and translation transform to the view?
Just setup your frame and bounds to the landscape size.
frame is computed from center and bounds, and is meaningless when a transform is applied.
I'm having some of the same issues here. I have a landscape app that I would like to add a navigation bar to. The problem is, the navigation controller, in fact view controllers in general, don't seem to want to work just in landscape.
I've tried to insulate the UINavigationController as much as possible from the transformation, but it's no good.
My structure is this:
In applicationDidFinishLaunching, I make a new, empty UIView, and add it as a subview of the window. Then, I rotate this view 90 degrees, and reset the bounds. Next, I add the view controller as a subview of that view, instead of directly to the window. The idea here is to not mess with the view controller's view itself, just its enclosing view.
The navigation bar and view do wind up rotated and positioned correctly, but they are only 320 pixels wide. My top-level view is laid out correctly: I made drawRect: fill with red, and I see red to the right of the navigation view.
After that, I thought maybe the view controller was getting its size info from its parent view's frame, but since the parent view is rotated, the frame is meaningless or at least incorrect. Next trick: put *another* view, unrotated, inside the rotated view, and put the view controller inside this nested view. That way, the frame it sees should be correct for a landscape layout.
But that doesn't work either, same behavior. I think the UIViewController is simply designed to always be in control of its own orientation. If it thinks it's in portrait, which it always does by default, it will lay out 320 pixels wide. The only way around that seems to be to override shouldAutorotateToInterfaceOrientation: . But then it still starts in portrait. Autorotation is not what many of us want, but I think that may be the best you can get with a view controller. I hope someone can show me I'm wrong.
The only avenue left seems to be to manage the navigation bar myself, and not use a view controller. But then I'll have to do the push/pop animations myself.
After tons of experiments, I have figured out when to do the transforms, and what to set to get landscape views a reality. I still have one nagging problem, but anyway it seems to be working. First you set up a global variable to hold the 90 degree rotation along with a translation to fix up what othewise is off the screen slightly.
The only flaw in this system is that you can't detect a mouse click in the leftmost 26 pixels of the screen. I believe this is because there is a status bar lurking underneath, and although not visible is gobbling up touches. Anybody know how to hide the status bar area so it won't take away my touches?
I sure wish apple had instead of creating a complex windowing system with all sorts of built-in functionality - most of which we DON"T WANT, should have instead left the system bare, so we could do what we want, and just published code for how to do it nicely if they want to imitate apple. all these built in windows and assumptions are just like microsoft windows, which always tries to force you to have one window, and operate a certain way.
You're right, you would need to rotate, change the frame to landscape and then offset the center by 80, -80. (Basically, going from 320x480 to 480x320).
It is a known problem with the status bar. I've found the below code (although, not tested), hopefully it will reset the edges and allow you to touch again.
The only flaw in this system is that you can't detect a mouse click in the leftmost 26 pixels of the screen. I believe this is because there is a status bar lurking underneath, and although not visible is gobbling up touches. Anybody know how to hide the status bar area so it won't take away my touches?
This is a known problem, and has nothing to do with rotation: that part of the screen simply doesn't respond to touches. Other threads here:
However! Not to worry, because it turns out this is only a bug in the simulator! I've verified that the status bar area *is* touchable on the actual iPhone.
When you're doing landscape mode, and storing your view in a nib (separate from the MainWindow.xib file), it's actually fairly easy to deal with this problem. In your applicationDidFinishLaunching, after setting the view, manually change the bounds, rotate, and re-center. You don't need to do a manual (+80, -80) offset, just align the center with the window's center after rotating, like so:
In my case, rootController is an outlet to a UIViewController subclass instance contained in the nib. The order here is important - add the view to the window first, then re-size, rotate, and re-center. The degreesToRadian call is just a function macro used to avoid dealing with radians, it looks like this:
Code:
#define degreesToRadian(x) (M_PI * x / 180.0)
This version, unlike most of the solutions I've seen, should continue to work if the iPhone's screen size changes.
This almost works for me - but if my rootController.view is (or has any subviews of) type UIImageView, the image is immediately expanded to 480x320, regardless of the original size of the image.
I had to add re-create the CGRect manually to restore the image to the desired size (larger-than-screen) and position (negative offset), like this:
This almost works for me - but if my rootController.view is (or has any subviews of) type UIImageView, the image is immediately expanded to 480x320, regardless of the original size of the image.
I had to add re-create the CGRect manually to restore the image to the desired size (larger-than-screen) and position (negative offset), like this: