Iphone Application : Building Rotatable and Resizable User Interfaces - Reframing Controls on Rotation

11/6/2012 8:07:12 PM
Setting Up the Project

Create a new view-based iPhone application project and name it Reframe.

Adding Outlets and Properties

In this exercise, you’ll manually resize and reposition three UI elements: two buttons (UIButton) and one label (UILabel). Because we’ll need to access these programmatically, we’ll first edit the interface and implementation files to include outlets and properties for each of these objects.

Open the ReframeViewController.h file, and edit it to include IBOutlet declarations and @property directives for buttonOne, buttonTwo, and viewLabel, as shown in Listing 1.

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

@interface ReframeViewController : UIViewController {
    IBOutlet UIButton *buttonOne;
    IBOutlet UIButton *buttonTwo;
    IBOutlet UILabel *viewLabel;

@property (nonatomic,retain) UIButton *buttonOne;
@property (nonatomic,retain) UIButton *buttonTwo;
@property (nonatomic,retain) UILabel *viewLabel;


Save your changes, then edit ReframeViewController.m, adding the appropriate @synthesize directives for buttonOne, buttonTwo, and viewLabel, immediately following the @implementation line:

@synthesize buttonOne;
@synthesize buttonTwo;
@synthesize viewLabel;

Releasing the Objects

Edit the dealloc method in ReframeViewController.m to release the label and button we’ve retained:

- (void)dealloc {
    [buttonOne release];
    [buttonTwo release];
    [viewLabel release];
    [super dealloc];

Enabling Rotation

Even when you aren’t going to be taking advantage of the autoresizing/autorotation capabilities in Interface Builder, you must still enable rotation in the shouldAutorotateToInterfaceOrientation: method. Update ReframeViewController.m to include the implementation you added in the earlier lesson:

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

With the exception of the logic to detect and handle the reframing of our interface elements, that finishes the setup of our application. Now, let’s create the default view that will be displayed when the application first loads.

Creating the Interface

We’ve now reached the point in the project where the one big caveat of reframing becomes apparent—keeping track of interface coordinates and sizes. Although we have the opportunity to lay out the interface in Interface Builder, we’ll need to make note of where all of the different elements are. Why? Because each time the screen changes rotation, we’ll be resetting their positions in the view. There is no “return to default positions” method, so even the initial layout we create will have to be coded using x,y coordinates and sizes so that we can call it back up when needed. Let’s begin.

Open the ReframeViewController.xib file and its view in Interface Builder.

Disabling Autosizing

Before doing anything else, click within the view to select it, and then open the Attributes Inspector (Command+1). Within the View settings section, uncheck the Autoresize Subviews check box, as shown in Figure 1.

Figure 1. Disabling autoresizing when manually resizing and positioning controls.

If you forget to disable the autoresize attribute in the view, your application code will manually resize/reposition the UI elements at the same time the iOS tries to do it for you. The result can be a jumbled mess and several minutes of head scratching!

Laying Out the View... Once

Your next step is to lay out the view exactly as you would in any other app. Recall that we added outlets for two buttons and a label; using the Library, click and drag those elements into your view now. Title the label Reframing and position it at the top of the view. Set the button titles to Button 1 and Button 2 and place them under the label. Your final layout should resemble Figure 2.

Figure 2. Start by laying out the view like a normal application.

When you have the layout you want, you’ll need to determine what the current frame attributes are for each of your objects. You can get this information from the Size Inspector.

Start by selecting the label and opening the Size Inspector (Command+3). Click the dot in the upper-right corner of the Size & Position settings to set it as the origin point for measuring coordinates. Next, make sure that the drop-down menu is set to Frame, as shown in Figure 3.

Figure 3. Configure the Size & Position settings to show the information you need to collect.

Now, write down the X, Y, W (width), and H (height) attributes for the label. This represents the frame property of the object within your view. Repeat this process for the two buttons. You should end up with a list of four values for each of your objects. Our frame values are listed here for comparison:

  • Label: X: 95.0, Y: 15.0, W: 130.0, H: 20.0

  • Button 1: X: 20.0, Y: 50.0, W: 280.0, H: 190.0

  • Button 2: X: 20.0, Y: 250.0, W: 280.0, H: 190.0

Before doing anything else, save your view! We’ll be making some changes in the next section that you’ll want to undo.

Did you Know?

If you want to follow our example exactly, feel free to enter the X, Y, W, and H point values we’ve provided for the values of your objects in the Size Inspector. Doing this will resize and reposition your view elements to match the one here!

Laying Out the View... Again

Your next step is to lay out the view exactly as you would in any other app. Wait a sec; this sounds very familiar. Why do we want to lay out the view again? The answer is simple. We’ve collected all of the frame properties that we’ll need to configure the portrait view, but we haven’t yet defined where the label and buttons will be in the landscape view. To get this information, we’ll lay the view out again in landscape mode, collect all the location and size attributes, and then discard those changes.

The process is identical to what you’ve already done—the only difference is that you need to click the rotate arrow in Interface Builder to rotate the view. Once rotated, resize and reposition all the existing elements so that they look the way you want them to appear when in landscape orientation on your iPhone. Because we’ll be setting the positions and sizes programmatically, the sky is the limit for how you arrange the display. To follow our example, stretch Button 1 across the top of the view and Button 2 across the button. Position the Reframing label in the middle, as shown in Figure 4.

Figure 4. Lay the view out as you’d like it to appear in landscape mode.

As before, when the view is exactly as you want it to appear, use the Size Inspector (Command+3) to collect the x,y coordinates and height and width of all of the UI elements. Our landscape frame values are provided here for comparison:

  • Label: X: 175.0, Y: 140.0, W: 130.0, H: 20.0

  • Button 1: X: 20.0, Y: 20.0, W: 440.0, H: 100.0

  • Button 2: X: 20.0, Y: 180.0, W: 440.0, H: 100.0

When you’ve collected the landscape frame attributes, undo the changes by using Edit, Undo (Command+Z), or close ReframeViewController.xib (not saving the changes).

Connecting the Outlets

Before jumping back into Xcode to finish the implementation, we still need to connect the label and buttons to the outlets (viewLabel, buttonOne, and buttonTwo) that we added at the start of the project. Open ReframeViewController.xib again (if you closed it in the last step), and make sure that the view window and Document window are both visible onscreen.

Next, Control-drag from the File’s Owner icon to the label and two buttons, choosing viewLabel, buttonOne, and buttonTwo as appropriate. Figure 5 demonstrates the connection from the Reframing label to the viewLabel outlet.

Figure 5. Finish up the interface by connecting the label and buttons to their corresponding outlets.

Save the XIB file and return to Xcode to finish up the project!

Implementing the Reframing Logic

Now that you’ve built the view and captured the values for the label and button frames in both portrait and landscape views, the only thing that remains is detecting when the iPhone is ready to rotate and reframing appropriately.

The willRotateToInterfaceOrientation:toInterfaceOrientation:duration: method is invoked automatically whenever the iPhone interface needs to rotate. We’ll compare toInterfaceOrientation parameter to the different iPhone orientation constants to identify whether we should be using the frames for a landscape or portrait view.

Open the ReframeViewController.m file in Xcode and add the method shown in Listing 2.

Listing 2.
 1: -(void)willRotateToInterfaceOrientation:
 2: (UIInterfaceOrientation)toInterfaceOrientation
 3:                                duration:(NSTimeInterval)duration {
 5:     [super willRotateToInterfaceOrientation:toInterfaceOrientation
 6:                                    duration:duration];
 8:     if (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight ||
 9:         toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) {
10:         viewLabel.frame=CGRectMake(175.0,140.0,130.0,20.0);
11:         buttonOne.frame=CGRectMake(20.0,20.0,440.0,100.0);
12:         buttonTwo.frame=CGRectMake(20.0,180.0,440.0,100.0);
13:     } else {
14:         viewLabel.frame=CGRectMake(95.0,15.0,130.0,20.0);
15:         buttonOne.frame=CGRectMake(20.0,50.0,280.0,190.0);
16:         buttonTwo.frame=CGRectMake(20.0,250.0,280.0,190.0);
17:     }
18: }


The logic is straightforward. To start, we need to make sure that any parent objects are notified that the view is about to rotate. So, in lines 5–6, we pass the same willRotateToInterfaceOrientation:toInterfaceOrientation:duration: message to the parent object super.

In lines 8–12 we compare the incoming parameter toInterfaceOrientation to the landscape orientation constants. If either of these match, we reframe the label and buttons to their landscape layouts by assigning the frame property to the output of the CGRectMake() function. The input to CGRectMake() is nothing more than the X, Y, W, and H values we collected earlier in Interface Builder.

Lines 13–16 handle the “other” orientation: portrait orientation. If the iPhone isn’t rotated into a landscape orientation, the only other possibility is portrait. Again, the frame values that we assign are nothing more than the values identified using the Size Inspector in Interface Builder.

And with this simple method, the Reframe project is now complete! You now have the capability of creating interfaces that rearrange themselves when users rotate their phones.

We still have one more approach to cover. In this final project, instead of rearranging a view in landscape orientation, we’ll replace the view altogether!

Top 10
OCUK Limited Edition P170EM - A Great Screen And Balanced Setup
Toshiba Satellite Pro L830 10J – An Affordable 13.3in Laptop
Programming the iPhone User : UX Anti-Patterns - Memory Lapse
SQL Server 2005 Security : Protecting SQL Server 2005, How Hackers Attack SQL Server
Sky vs. Virgin - Which Smart Service Comes Out On Top?
SQL Server 2012 : SQL Server Audit (part 2) - Auditing Server Events, Auditing Database Events
Which Components Have Hit The Sweet Spot? (Part 1)
2015 Audi S3 Sedan Review (Part 2)
Nikon Coolpix P520 - A Pretty Good Update Version Of P510 (Part 2)
The Best Cameras For Children (Part 1)
- First look: Apple Watch

- 3 Tips for Maintaining Your Cell Phone Battery (part 1)

- 3 Tips for Maintaining Your Cell Phone Battery (part 2)
- How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010 (Part 1)

- How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010 (Part 2)

- How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010 (Part 3)
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