Page 1 of 1

iPhone Development Part 2 [Swapping between landscape and portrait views] Rate Topic: ***-- 2 Votes

#1 BetaWar  Icon User is online

  • #include "soul.h"
  • member icon

Reputation: 1148
  • View blog
  • Posts: 7,145
  • Joined: 07-September 06

Posted 06 December 2009 - 10:05 PM

iPhone Development Part 2
[Swapping between landscape and portrait views]

In this tutorial we will be covering:
Creating an app that allows for iPhone rotation from side to side, as well as creating functions that take multiple arguments and writing a custom class, additionally we will be adding segments to our segmented control and making the various segments act differently based on which one is clicked.

Setting up for the rotation:
So, we have finished the first tutorial, but what now? Well, the one common thought would be to add landscape view mode into the application.

If you are wondering why someone would want to put their application into landscape view here are a few reasons:
- Wider screen
- Increased zoom without having to scroll horizontally
- Easier on the eyes (because most of the information on the screen will be larger than it was in portrait mode)

To start off working on this modification (yes, we are going to be modifying the previous program) we will need to butcher it a bit. This is because we did all the previous code within the AppDelegate class, which is really only meant to delegate the initial memory needed for the application then hand control over to another class. It also cleans up after the application has finished (by releasing the class that had control).

In the last tutorial we left off with this code:
 #import <UIKit/UIKit.h>

@interface Hello_world_tutAppDelegate : NSObject <UIApplicationDelegate> {
	UIWindow *window;
	UILabel* myLabel;
	IBOutlet UISegmentedControl* myButton;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;

@end

@implementation Hello_world_tutAppDelegate

@synthesize window;


- (void)applicationDidFinishLaunching:(UIApplication *)application {	
	// Override point for customization after application launch
	[window makeKeyAndVisible];
	myLabel = [[UILabel alloc] initWithFrame:CGRectMake(5, 15, 310, 200)];
	myLabel.text = @"Hello World";
	 [myLabel setAlpha:0.5];
	 [window addSubview:myLabel];
	myButton = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObject:@"Click to release myLabel"]];
	myButton.momentary = YES;
	myButton.center = CGPointMake(160,400);
	 [myButton addTarget:self action:@selector(ButtonPress)	forControlEvents:UIControlEventValueChanged];
	 [window addSubview:myButton];
}

- (void)ButtonPress {
	if (myLabel != nil) {
		 [myLabel release];
		myLabel = nil;
	}
	UIAlertView* alert = [[UIAlertView alloc]  initWithTitle:@"Event" message:@"The button was pressed."  delegate:self cancelButtonTitle:@"Okay" otherButtonTitles:nil];
	 [alert show];
	 [alert release];
}

- (void)dealloc {
	 [myButton release];
	if(myLabel != nil){
		 [myLabel release];
	}
	[window release];
	[super dealloc];
}


@end

int main(int argc, char *argv[]) {
	
	NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
	int retVal = UIApplicationMain(argc, argv, nil, nil);
	[pool release];
	return retVal;
}



Start off by implementing the new class (which will be holding all we are about to cut out of the old one). That can be accomplished by using some code like so:
@interface myAppView UIViewController{
	UILabel* myLabel;
	IBOutlet UISegmentedControl* myButton;
	IBOutlet UIScrollView* myView;
} 
@end


That takes care of defining all the variables we will be using in this class.

NOTICE – One of the variables is a UIScrollView. This allows us to add subViews to it and it will scroll them when the output is outside the bounds of the view, we don’t have to worry about making the scrollbar work it just does.

Now let’s implement that class (myAppView):
@implementation myAppView


The next function is used to load the view of the UIViewController, which is a required function, and is also the standard one for outputting things to the ViewController. Given that we will be setting up all the variables in here:
- (void)loadView{
	myView = [[UIScrollView alloc] initWithFrame:CGMakeRect(0, 20, 320, 460)];
	[myView setContentSize:CGSizeMake(320, 480)];
	[myView setScrollEnabled:YES];
	[myView setClipsToBounds:YES];

	myLabel = [[UILabel alloc] initWithFrame:CGRectMake(5, 20, 310, 200)];
	myLabel.text = @”Hello World”;
	[myView addSubview:myLabel];

	myButton = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObject:@”Click the release myLabel”]];
	myButton.momentary = YES;
	myButton.segmentedControlStyle = UISegmentedControlStyleBar;
	[myButton insertSegmentWithTitle:@”Or click me to alert” atIndex:1 animated:TRUE];
	[myButton setWidth:120 forSegmentAt:1];
	myButton.center = CGPointMake(160, 400);
	[myButton addTarget:self action:@selector(ButtonPress:) forControlEvents:UIControlEventChanged];
	[myView addSubview:myButton];
	[self setView:myView];
}


This goes through creates the scroll view, sets its size to 320 wide and 460 tall with a 20 pixel offset from the top (to not overlap the info bar). Then it sets its content size to 320 by 480 (the max screen size available), and tells it to allow scrolling while still clipping the view at its own bounds.

After that we initialize the label again with the exact same way we did before, but we add it to myView instead of window.

Once that is completed we set up the buttons. While it starts off the same we modify it to have a different style (UISegmentedControlStyleBar) which makes it smaller, and we add a second segment (which will make an alert fire when clicked). The animated:TRUE makes the bar of buttons appear in a wiping tween. This is followed by setting the size for the second segment and the rest is pretty much the same (with the exception of ButtonPress:, which has been changed (added the : ) to allow for send the segment ID to the function.

Now that we have completed this lets set up the button press function:
- (void)ButtonPress:(id)sender {
	if([sender selectedSegmentIndex] == 0){
		if(myLabel != nil){
			[myLabel release];
			myLabel = nil;
		}
	}
	else{
		[self makeAlert:@”Title” message:@”Message”];
	}
}


This checks the segment that was clicked, if it is the first it releases myLabel’s memory, if the second it calls makeAlert with 2 parameters.

At this point we should set up makeAlert:
- (void)makeAlert:(NSString*)title message:(NSString*)msg{
	UIAlertView* alert = [[UIAlertView alloc] initWithTitle:title message:msg delegate:self cancelButtonTitle:@”Okay” otherButtonTitles:nil];
	[alert show];
	[alert release];
}


Now, that does exactly the same thing it did before, but it uses the parameters sent into the function instead of hard-coded variables.

The only thing left with this implementation is to finish implementing the required (standard) functions:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
	return YES;
}
- (void)didReceiveMemoryWarning{
	[super didReceiveMemoryWarning];
}
- (void)viewDidUnload{
}
- (void)dealloc{
	if(myLabel != nil){
		[myLabel release];
	}
	[myButton release];
	[myView release];
	[super dealloc];
}
@end


This tells the UIViewController to auto rotate to all available screen orientations (top, left, right and upside-down). If the class receives a memory warning it sends it up the chain. If it is the top of the chain it will just release all available (it pretty much calls the dealloc function).

The entire class looks like so:
 @interface myAppView: UIViewController{
	UILabel* myLabel;
	IBOutlet UISegmentedControl* myButton;
	IBOutlet UIScrollView* myView;
}
@end

@implementation myAppView
- (void)loadView{
	myView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 20, 320, 460)];
	 [myView setContentSize:CGSizeMake(320, 480)];
	 [myView setScrollEnabled:YES];
	 [myView setClipsToBounds:YES];

	myLabel = [[UILabel alloc] initWithFrame:CGRectMake(5, 20, 310, 200)];
	myLabel.text = @"Hello World";
	 [myView addSubview:myLabel];

	myButton = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObject:@"Click to release myLabel"]];
	myButton.momentary = YES;
	myButton.segmentedControlStyle = UISegmentedControlStyleBar;
	 [myButton insertSegmentWithTitle:@"Or click me to alert" atIndex:1 animated:TRUE];
	 [myButton setWidth:120 forSegmentAtIndex:1];
	myButton.center = CGPointMake(160,400);
	 [myButton addTarget:self action:@selector(ButtonPress:) forControlEvents:UIControlEventValueChanged];
	 [myView addSubview:myButton];
	 [self setView:myView];
}

- (void)makeAlert:(NSString*)title message:(NSString*)msg{
	UIAlertView* alert = [
	 [UIAlertView alloc]
	 initWithTitle:title
	 message:msg
	 delegate:self
	 cancelButtonTitle:@"Okay"
	 otherButtonTitles:nil
	 ];
	 [alert show];
	 [alert release];
}

- (void)ButtonPress:(id)sender {
	if([sender selectedSegmentIndex] == 0){
		if (myLabel != nil) {
			 [myLabel release];
			myLabel = nil;
		}
	}
	else{
		 [self makeAlert:@"Title" message:@"Message"];
	}
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
	return YES;
}

- (void)didReceiveMemoryWarning{
	[super didReceiveMemoryWarning];
}

- (void)viewDidUnload{
}

- (void)dealloc{
	if(myLabel != nil){
		 [myLabel release];
	}
	[myButton release];
	[myView release];
	[super dealloc];
}
@end



The only thing left to do is remove all the extra code from the previous program. Once you strip it clean it looks like so:
 #import <UIKit/UIKit.h>

@interface Hello_world_tutAppDelegate : NSObject <UIApplicationDelegate> {
	UIWindow *window;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;

@end

@implementation Hello_world_tutAppDelegate

@synthesize window;


- (void)applicationDidFinishLaunching:(UIApplication *)application {	
	// Override point for customization after application launch
	[window makeKeyAndVisible];
}

- (void)dealloc {
	[window release];
	[super dealloc];
}


@end

int main(int argc, char *argv[]) {
	NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
	int retVal = UIApplicationMain(argc, argv, nil, nil);
	[pool release];
	return retVal;
}



So, now we have the shell of our old application. It is now time to insert all the updated code into it so we can see everything working out nicely as the application runs. To do that we actually have very little code to add, in fact all we really need to do is four lines of code to the shell, which changes this code:

 @interface Hello_world_tutAppDelegate : NSObject <UIApplicationDelegate> {
	UIWindow *window;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;

@end

@implementation Hello_world_tutAppDelegate

@synthesize window;


- (void)applicationDidFinishLaunching:(UIApplication *)application {	
	// Override point for customization after application launch
	[window makeKeyAndVisible];
}

- (void)dealloc {
	[window release];
	[super dealloc];
}


To this:
 @interface Hello_world_tutAppDelegate : NSObject <UIApplicationDelegate> {
	UIWindow *window;
	IBOutlet myAppView* app;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;

@end

@implementation Hello_world_tutAppDelegate

@synthesize window;


- (void)applicationDidFinishLaunching:(UIApplication *)application {	
	// Override point for customization after application launch
	[window makeKeyAndVisible];
	app = [[MyAppView alloc] init];
	[window addSubview:app.view];
}

- (void)dealloc {
	[app release];
	[window release];
	[super dealloc];
}


That wasn’t too bad. Now it is time to combine it all and show the final code:
 #import <UIKit/UIKit.h>

@interface myAppView: UIViewController{
	UILabel* myLabel;
	IBOutlet UISegmentedControl* myButton;
	IBOutlet UIScrollView* myView;
}
@end

@implementation myAppView
- (void)loadView{
	myView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 20, 320, 460)];
	 [myView setContentSize:CGSizeMake(320, 480)];
	 [myView setScrollEnabled:YES];
	 [myView setClipsToBounds:YES];

	myLabel = [[UILabel alloc] initWithFrame:CGRectMake(5, 20, 310, 200)];
	myLabel.text = @"Hello World";
	 [myView addSubview:myLabel];

	myButton = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObject:@"Click to release myLabel"]];
	myButton.momentary = YES;
	myButton.segmentedControlStyle = UISegmentedControlStyleBar;
	 [myButton insertSegmentWithTitle:@"Or click me to alert" atIndex:1 animated:TRUE];
	 [myButton setWidth:120 forSegmentAtIndex:1];
	myButton.center = CGPointMake(160,400);
	 [myButton addTarget:self action:@selector(ButtonPress:) forControlEvents:UIControlEventValueChanged];
	 [myView addSubview:myButton];
	 [self setView:myView];
}

- (void)makeAlert:(NSString*)title message:(NSString*)msg{
	UIAlertView* alert = [
		  [UIAlertView alloc]
		 initWithTitle:title
		 message:msg
		 delegate:self
		 cancelButtonTitle:@"Okay"
		 otherButtonTitles:nil
	 ];
	 [alert show];
	 [alert release];
}

- (void)ButtonPress:(id)sender {
	if([sender selectedSegmentIndex] == 0){
		if (myLabel != nil) {
			[myLabel release];
			myLabel = nil;
		}
	}
	else{
		 [self makeAlert:@"Title" message:@"Message"];
	}
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
	return YES;
}

- (void)didReceiveMemoryWarning{
	[super didReceiveMemoryWarning];
}

- (void)viewDidUnload{
}

- (void)dealloc{
	if(myLabel != nil){
		 [myLabel release];
	}
	[myButton release];
	[myView release];
	[super dealloc];
}
@end

@interface Hello_world_tutAppDelegate : NSObject <UIApplicationDelegate>{
	UIWindow* window;
	IBOutlet myAppView* app;
}
@property (nonatomic, retain) IBOutlet UIWindow* window;
@end

@implementation Hello_world_tutAppDelegate
@synthesize window;
- (void)applicationDidFinishLaunching:(UIApplication *)application{
	[window makeKeyAndVisible];
	app = [[myAppView alloc] init];
	 [window addSubview:app.view];
}

- (void)dealloc{
	 [app release];
	[window release];
	[super dealloc];
}
@end

int main(int argc, char *argv[]){
	NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
	int retVal = UIApplicationMain(argc, argv, nil, nil);
	[pool release];
	return retVal;
}



Congratulations, you have officially created an application that works with multiple orientations and allows for content that doesn’t fit on a single screen!

Is This A Good Question/Topic? 0
  • +

Page 1 of 1