MOBILE

Iphone Application : Building Rotatable and Resizable User Interfaces - Swapping Views on Rotation

11/6/2012 8:09:33 PM
Some applications display entirely different user interfaces depending on the iPhone’s orientation. The iPod application, for example, displays a scrolling list of songs in portrait mode and a “flickable” Cover Flow view of albums when held in landscape. You, too, can create applications that dramatically alter their appearance by simply switching between views when the phone is rotated. Our last tutorial this hour will be short, sweet, and give you the flexibility to manage your landscape and portrait views all within the comfort of Interface Builder.

Setting Up the Project

Create a new project named Swapper using the View-Based iPhone Application template. Although this includes a single view already (which we’ll use for the default portrait display), we need to supplement it with a second landscape view.

Adding Outlets and Properties

This application won’t implement any real user interface elements, but we will need to access two UIView instances programmatically.

Open the SwapperViewController.h file and edit it to include IBOutlet declarations and @property directives for portraitView, and landscapeView. The result should match Listing 1.

Listing 1.
#import <UIKit/UIKit.h>

@interface ReframeViewController : UIViewController {
    IBOutlet UIView *portraitView;
    IBOutlet UIView *landscapeView;
}

@property (nonatomic,retain) UIView *portraitView;
@property (nonatomic,retain) UIView *landscapeView;

@end

You know the routine. Save your changes, then edit SwapperViewController.m implementation file, adding the appropriate @synthesize directives immediately following the @implementation line:

@synthesize portraitView;
@synthesize landscapeView;

Releasing the Objects

Edit the dealloc method in ReframeViewController.m to release the two views we’ve retained.

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

Enabling Rotation

Once more, we need to enable rotation in order for the iPhone to properly react when it changes orientation. Unlike the previous two implementations of shouldAutorotateToInterfaceOrientation:, this time, we’ll only allow rotate between the two landscape modes and upright portrait.

Update ReframeViewController.m to include the implementation in Listing 2.

Listing 2.
- (BOOL)shouldAutorotateToInterfaceOrientation:
           (UIInterfaceOrientation)interfaceOrientation {
    return (interfaceOrientation == UIInterfaceOrientationPortrait ||
            interfaceOrientation == UIInterfaceOrientationLandscapeRight ||
            interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}

The incoming interfaceOrientation parameter is compared to the UIInterfaceOrientationPortrait, UIInterfaceOrientationLandscapeRight, and UIInterfaceOrientationLandscapeLeft. If it matches, rotation is allowed. As you might surmise, this covers all of the possible orientations except upside-down portrait (UIInterfaceOrientationPortraitUpsideDown)—which we’ll disable this time around.

Adding a Degree to Radians Constant

Later in this exercise, we’re going to need to call a special Core Graphics method to define how to rotate views. The method requires a value to be passed in radians rather than degrees. In other words, rather than saying we want to rotate the view 90 degrees, we have to tell it we want to rotate 1.57 radians. To help us handle the conversion, we will define a constant for the conversion factor. Multiplying degrees by the constant gets us the resulting value in radians.

To define the constant, add the following line after the #import line in SwapperViewController.m:

#define deg2rad (3.1415926/180.0)

Creating the Interface

When swapping views, the sky is the limit for the design. You build them exactly as you would in any other application. The only difference is that if you have multiple views handled by a single view controller, you’ll need to define outlets that encompass all the interface elements.

In this example, we’ll just demonstrate how to swap views, so our work in Interface Builder will be a piece of cake.

Creating the Views

Open SwapperViewController.xib and drag a new instance of the UIView object from the Library to the Document window. Don’t put the UIView inside the existing view. It should be added as a new separate view within the XIB file, as shown in Figure 1.

Figure 1. Add a second view to the XIB file.


Now, open each of the views and add a label to tell them apart. We’ve set the background color of each view to be different as well. You’re welcome to add other controls and design the view as you see fit. Our finished landscape and portrait views are seen in Figure 2.

Figure 2. Edit the two views so that you can tell them apart.

Did you Know?

To differentiate between the two views within the Interface Builder Document window, you can edit the name of each view just like you would edit a filename in the Finder!


Connecting the Outlets

To finish up in Interface Builder, Control-drag from the File’s Owner icon to each of the views. Connect the portrait view to the portraitView outlet, as shown in Figure 3, and the landscape view to landscapeView.

Figure 3. Connect the views to their corresponding outlets.

Save the XIB file and return to Xcode to finish up the Swapper implementation.

Implementing the View-Swapping Logic

For the most part, swapping views is actually easier than the reframing logic we implemented in the last project—with one small exception. Even though we designed one of the views to be in landscape view, it doesn’t “know” that it is supposed to be displayed in a landscape orientation. Before we can display it, we need to rotate it and define how big it is.

Understanding the View-Rotation Logic

Each time we change orientation, we’ll go through three steps—swapping the view, rotating the view to the proper orientation through the transform property, and setting the view’s origin and size via the bounds property.

For example, assume we’re rotating to landscape right orientation:

1.
First, we swap out the view by assigning self.view, which contains the current view of the view controller, to the landscapeView instance variable. If we left things at that, the view would properly switch, but it wouldn’t be rotated into the landscape orientation. A landscape view displayed in a portrait orientation isn’t a pretty thing! For example:

self.view=landscapeView;

2.
Next, to deal with the rotation, we define the transform property of the view. This property determines how the view will be altered before it is displayed. To meet our needs, we’ll have to rotate the view 90 degrees to the right (for landscape right), –90 degrees to the left (for landscape left), and 0 degrees for portrait. As luck would have it, the Core Graphics C function, CGAffineTransformMakeRotation(), accepts a rotation value in radians, and provides an appropriate structure to the transform property handle the rotation. For example:

self.view.transform=CGAffineTransformMakeRotation(deg2rad*(90));

By the Way

Note that we multiply the rotation in degrees (90, –90, and 0) by the constant deg2rad that we defined earlier so that CGAffineTransformMakeRotation() has the radian value it expects.

3.
The final step is to set the bounds property of the view. The bounds define the origin point and size of the view after it undergoes the transformation. A portrait iPhone view has an original point of 0,0 and a width and height of 320.0 and 460.0. A landscape view has the same origin point (0,0) but a width of 480.0, and a height of 300.0. As with the frame property, we can set bounds using the results of CGRectMake(). For example:

self.view.bounds=CGRectMake(0.0,0.0,480.0,320.0);

What Happened to 320×480? Where Are the Missing 20 Points?

The missing 20 points are taken up by the iPhone status bar. When the phone is in portrait mode, the points come off of the large (480) dimension. In landscape orientation, however, the status bar eats up the space on the smaller (320) dimension.


Now that you understand the steps, let’s take a look at the actual implementation.

Writing the View-Rotation Logic

As with the Reframing project, all this magic happens within a single method: willRotateToInterfaceOrientation:toInterfaceOrientation:duration:.

Open the SwapperViewController.m implementation file and implement the method as shown in Listing 2.

Listing2.
 1: -(void)willRotateToInterfaceOrientation:
 2:             (UIInterfaceOrientation)toInterfaceOrientation
 3:             duration:(NSTimeInterval)duration {
 4:
 5:     [super willRotateToInterfaceOrientation:toInterfaceOrientation
 6:                                    duration:duration];
 7:
 8:     if (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight) {
 9:         self.view=landscapeView;
10:         self.view.transform=CGAffineTransformMakeRotation(deg2rad*(90));
11:         self.view.bounds=CGRectMake(0.0,0.0,480.0,320.0);
12:     } else if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) {
13:         self.view=landscapeView;
14:         self.view.transform=CGAffineTransformMakeRotation(deg2rad*(-90));
15:         self.view.bounds=CGRectMake(0.0,0.0,480.0,320.0);
16:     } else {
17:         self.view=portraitView;
18:         self.view.transform=CGAffineTransformMakeRotation(0);
19:         self.view.bounds=CGRectMake(0.0,0.0,300.0,460.0);
20:     }
21: }

					  

Lines 5–6 pass the interface rotation message up to the parent object so that it can react appropriately.

Lines 8–11 handle rotation to the right (landscape right). Lines 12–15 deal with rotation to the left (landscape left). Finally, lines 16–19 configure the view for the default orientation, portrait.

Save the implementation file, and then choose Build and Run to test the application. As you rotate the phone or the iPhone simulator, your views should be swapped in and out appropriately.

Did you Know?

Although we used an if-then-else statement in this example, you could easily use a switch structure instead. The toInterfaceOrientation parameter and orientation constants are integer values, which means they can be evaluated directly in a switch statement.

Other  
 
Most View
Microsoft SharePoint 2010 Web Applications : Presentation Layer Overview - Ribbon (part 1)
The Cyber-athletic Revolution – E-sports’ Era (Part 1)
Windows Server 2003 : Implementing Software Restriction Policies (part 4) - Implementing Software Restriction Policies - Creating a Path Rule, Designating File Types
Sql Server 2012 : Hierarchical Data and the Relational Database - Populating the Hierarchy (part 1)
Two Is Better Than One - WD My Cloud Mirror
Programming ASP.NET 3.5 : Data Source-Based Data Binding (part 3) - List Controls
Windows 8 : Configuring networking (part 5) - Managing network settings - Understanding the dual TCP/IP stack in Windows 8, Configuring name resolution
Nikon Coolpix A – An Appealing Camera For Sharp Images (Part 2)
Canon PowerShot SX240 HS - A Powerful Perfection
LG Intuition Review - Skirts The Line Between Smartphone And Tablet (Part 2)
Popular Tags
Microsoft Access Microsoft Excel Microsoft OneNote Microsoft PowerPoint Microsoft Project Microsoft Visio Microsoft Word Active Directory Biztalk Exchange Server Microsoft LynC Server Microsoft Dynamic Sharepoint Sql Server Windows Server 2008 Windows Server 2012 Windows 7 Windows 8 Adobe Indesign Adobe Flash Professional Dreamweaver Adobe Illustrator Adobe After Effects Adobe Photoshop Adobe Fireworks Adobe Flash Catalyst Corel Painter X CorelDRAW X5 CorelDraw 10 QuarkXPress 8 windows Phone 7 windows Phone 8 BlackBerry Android Ipad Iphone iOS
Top 10
Review : Acer Aspire R13
Review : Microsoft Lumia 535
Review : Olympus OM-D E-M5 Mark II
TomTom Runner + MultiSport Cardio
Timex Ironman Run Trainer 2.0
Suunto Ambit3 Peak Sapphire HR
Polar M400
Garmin Forerunner 920XT
Sharepoint 2013 : Content Model and Managed Metadata - Publishing, Un-publishing, and Republishing
Sharepoint 2013 : Content Model and Managed Metadata - Content Type Hubs