Advertise Mobile SDKs Books Events Forum News Social Networking Support Us
Follow @iphonedevsdk on Twitter

Mockup & CodeGen, iPhone & iPad
($9.99)

Make your own iPhone apps
and run them live!
(free)

Manu
($0.99)

Want your application or service advertised on iPhone Dev SDK?

Go Back   iPhone Dev SDK Forum > iPhone SDK Development Forums > iPhone SDK Development

Reply
 
LinkBack Thread Tools Display Modes
Old 08-22-2008, 04:02 AM   #1 (permalink)
New Member
 
Join Date: Aug 2008
Posts: 39
Question How to create a view-wide transform

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?
ekbart is offline   Reply With Quote
Old 08-22-2008, 04:12 AM   #2 (permalink)
Registered Member
 
Jume's Avatar
 
Join Date: Jul 2008
Location: Slovenia, EU
Posts: 264
Send a message via Skype™ to Jume
Default

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.

Bye,
Jume
Jume is offline   Reply With Quote
Old 08-22-2008, 04:20 AM   #3 (permalink)
Registered Member
 
Stitch's Avatar
 
Join Date: Aug 2008
Posts: 401
Default

Try running this in your VC before you add the view to the subview

Code:
CGAffineTransform rotate = CGAffineTransformMakeRotation(1.57079633);
[myView setTransform:rotate];
May need tweaking a little
Stitch is offline   Reply With Quote
Old 08-22-2008, 04:35 AM   #4 (permalink)
New Member
 
Join Date: Aug 2008
Posts: 39
Default is this a clue?

I found in doing some search and saw some old code no longer compiles but has a call like this:

[[[myview superview] layer] setSublayerTransform:mylandscapeTransform];


so there is a method called setSublayerTransform but gosh NO DOCUMENTATION OR EXAMPLES thanks apple.
ekbart is offline   Reply With Quote
Old 08-22-2008, 04:49 AM   #5 (permalink)
New Member
 
Join Date: Aug 2008
Posts: 39
Default no go

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.

CGAffineTransform rotate = CGAffineTransformMakeRotation(1.57079633);
[myView setTransform:rotate];

and it has no effect on the subviews that were added. what about this mysterious sublayerTransform method?
ekbart is offline   Reply With Quote
Old 08-22-2008, 04:57 AM   #6 (permalink)
Registered Member
 
Stitch's Avatar
 
Join Date: Aug 2008
Posts: 401
Default

That's weird.

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];
Stitch is offline   Reply With Quote
Old 08-22-2008, 05:19 AM   #7 (permalink)
New Member
 
Join Date: Aug 2008
Posts: 39
Default aha progress but still struggling

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?
ekbart is offline   Reply With Quote
Old 08-22-2008, 05:20 AM   #8 (permalink)
Registered Member
 
Jume's Avatar
 
Join Date: Jul 2008
Location: Slovenia, EU
Posts: 264
Send a message via Skype™ to Jume
Default

Quote:
Originally Posted by Stitch View Post
That's weird.

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?
Jume is offline   Reply With Quote
Old 08-22-2008, 05:22 AM   #9 (permalink)
New Member
 
Join Date: Aug 2008
Posts: 39
Default aha

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!
ekbart is offline   Reply With Quote
Old 08-22-2008, 05:38 AM   #10 (permalink)
Registered Member
 
Jume's Avatar
 
Join Date: Jul 2008
Location: Slovenia, EU
Posts: 264
Send a message via Skype™ to Jume
Default

Quote:
Originally Posted by ekbart View Post
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?
Jume is offline   Reply With Quote
Old 08-22-2008, 05:54 AM   #11 (permalink)
Registered Member
 
Stitch's Avatar
 
Join Date: Aug 2008
Posts: 401
Default

Exactly, like I said, it will need some tweaking.

Here is the code for the VC:

Code:
- (void)loadView {
  MyView *tempMyView = [[MyView alloc] initWithFrame: < A FRAME >];
  self.myView = tempMyView ;
  [tempMyView release];
  CGAffineTransform rotate = CGAffineTransformMakeRotation(1.57079633);
  [myView setTransform:rotate];
  [self.view addSubview:myView];
}
Stitch is offline   Reply With Quote
Old 08-22-2008, 07:17 PM   #12 (permalink)
New Member
 
Join Date: Aug 2008
Posts: 39
Default Solution not that simple really.

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?
ekbart is offline   Reply With Quote
Old 08-22-2008, 08:13 PM   #13 (permalink)
New Member
 
Join Date: Apr 2008
Posts: 802
Default

Just setup your frame and bounds to the landscape size.
scottiphone is offline   Reply With Quote
Old 08-23-2008, 09:28 PM   #14 (permalink)
New Member
 
Join Date: Aug 2008
Posts: 125
Default

Quote:
Originally Posted by scottiphone View Post
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.
bhearn is offline   Reply With Quote
Old 08-24-2008, 12:28 AM   #15 (permalink)
New Member
 
Join Date: Aug 2008
Posts: 39
Default okay, a working solution finally

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.

Code:
g_landscape_transform = CGAffineTransformMakeRotation(1.57079633);
	g_landscape_transform = CGAffineTransformTranslate (g_landscape_transform, 80.0, +80.0);
Then inside you view handler when you create your view via initWithFrame:

Code:
- (id)initWithFrame:(CGRect)frame viewController:(LevelViewController *) arg_controller {
	self = [super initWithFrame:frame];
	if (self != nil) {
		self.viewController = arg_controller;
		self.transform = g_landscape_transform;
		self.bounds  = CGRectMake(0.0, 0.0, 480.0, 320.0);
		self.center  = CGPointMake (240.0, 160.0);
		[self setupSubviews];
	}
	return self;
}
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.
ekbart is offline   Reply With Quote
Old 08-24-2008, 04:21 AM   #16 (permalink)
Registered Member
 
Stitch's Avatar
 
Join Date: Aug 2008
Posts: 401
Default

Glad you got it working.

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.

Code:
- (void)viewDidLoad {
  CGRect frame = navController.view.frame;
  frame.origin.y = 0.0;
  navController.view.frame = frame;
}
Stitch is offline   Reply With Quote
Old 08-24-2008, 01:50 PM   #17 (permalink)
New Member
 
Join Date: Aug 2008
Posts: 125
Default

Quote:
Originally Posted by ekbart View Post
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:

http://www.iphonedevsdk.com/forum/ip...bar-place.html

http://www.iphonedevsdk.com/forum/ip...touchable.html

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.
bhearn is offline   Reply With Quote
Old 08-25-2008, 09:55 AM   #18 (permalink)
New Member
 
Join Date: Apr 2008
Posts: 420
Send a message via AIM to jeff_lamarche Send a message via Yahoo to jeff_lamarche
Default

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:

Code:
	[window addSubview:rootController.view];
	// Override point for customization after app launch	
        [window makeKeyAndVisible];
	[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:NO];
	[UIApplication sharedApplication].isIdleTimerDisabled = YES;
	
	
	UIScreen *screen = [UIScreen mainScreen];
	rootController.view.bounds = CGRectMake(0, 0, screen.bounds.size.height, screen.bounds.size.width);
	rootController.view.transform = CGAffineTransformConcat(rootController.view.transform, CGAffineTransformMakeRotation(degreesToRadian(90)));
	rootController.view.center = window.center;
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.
__________________
Check out my iPhone Dev Blog
You can send me e-mail at my forum username at mac dot com.
jeff_lamarche is offline   Reply With Quote
Old 09-12-2008, 04:37 AM   #19 (permalink)
Registered Member
 
Join Date: Jul 2008
Posts: 97
Default

thank u very much, finally something simple that actually working
Saurman is offline   Reply With Quote
Old 01-06-2009, 12:26 AM   #20 (permalink)
Noob
 
Join Date: Jan 2009
Location: Boston, MA
Posts: 20
Default

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:

myView.bounds = CGRectMake(0, 0, screen.bounds.size.height, screen.bounds.size.width);
myView.transform = CGAffineTransformConcat(myView.transform, CGAffineTransformMakeRotation(M_PI / 2));
myView.center = window.center;

CGRect myFrame = myView.frame;
myFrame.origin.x = 0.0;
myFrame.origin.y = -400.0;
myFrame.size.height = 1281.0;
myFrame.size.width = 201.0;

myView.frame = myFrame;

Now, it works .

My thanks to those who have come before me!
kordos is offline   Reply With Quote
Old 02-15-2009, 10:05 AM   #21 (permalink)
Registered Member
 
Join Date: Jan 2009
Posts: 35
Unhappy Is not working probably!

Quote:
Originally Posted by kordos View Post
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:

myView.bounds = CGRectMake(0, 0, screen.bounds.size.height, screen.bounds.size.width);
myView.transform = CGAffineTransformConcat(myView.transform, CGAffineTransformMakeRotation(M_PI / 2));
myView.center = window.center;

CGRect myFrame = myView.frame;
myFrame.origin.x = 0.0;
myFrame.origin.y = -400.0;
myFrame.size.height = 1281.0;
myFrame.size.width = 201.0;

myView.frame = myFrame;

Now, it works .

My thanks to those who have come before me!
debug console return me symbol(s) not found but when add application services disappear but give me another problem exit with status 1;
farshadmb is offline   Reply With Quote
Reply

Bookmarks

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On



» Advertisements
» Online Users: 327
22 members and 305 guests
@sandris, ADY, BrianSlick, dacapo, Dani77, djohnson, dre, HDshot, HemiMG, JasonR, MarkC, mer10, nibeck, prchn4christ, ryandb2, spiderguy84, themathminister, timle8n1, tomtom100, vogueestylee, vvenkatachallam
Most users ever online was 1,187, 10-11-2011 at 08:09 AM.
» Stats
Members: 158,883
Threads: 89,229
Posts: 380,763
Top Poster: BrianSlick (7,129)
Welcome to our newest member, vvenkatachallam
Powered by vBadvanced CMPS v3.1.0

All times are GMT -5. The time now is 02:08 PM.
Powered by vBulletin® Version 3.8.0
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.
Search Engine Friendly URLs by vBSEO 3.3.0