1. Trang chủ >
  2. Công Nghệ Thông Tin >
  3. Kỹ thuật lập trình >

2  Reacting to Rotation Gestures

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (8.37 MB, 640 trang )


Discussion

The UIRotationGestureRecognizer, as its name implies, is the perfect candidate among

gesture recognizers to detect rotation gestures and to help you build more intuitive

graphical user interfaces. For instance, when the user encounters an image on the screen

in your application in full-screen mode, it is quite intuitive for her to attempt to correct

the orientation by rotating the image.

The UIRotationGestureRecognizer class implements a property named rotation that

specifies the total amount and direction of rotation requested by the user’s gesture, in

radians. The rotation is determined from the fingers’ initial position (UIGestureRecog

nizerStateBegan) and final position (UIGestureRecognizerStateEnded).

To rotate UI elements that inherit from UIView class, you can pass the rotation property

of the rotation gesture recognizer to the CGAffineTransformMakeRotation function to

make an affine transform, as shown in the example.

The code in this recipe’s Solution passes the current object, in this case a view controller,

to the target of the rotation gesture recognizer. The target selector is specified as han

dleRotations:, a method we have to implement. But before we do that, let’s have a look

at the header file of our view controller:

#import

@interface RootViewController

@protected

UILabel

UIRotationGestureRecognizer

CGFloat

}



: UIViewController {

*helloWorldLabel;

*rotationGestureRecognizer;

rotationAngleInRadians;



@property (retain) UIRotationGestureRecognizer *rotationGestureRecognizer;

@property (retain) IBOutlet UILabel

*helloWorldLabel;

@property (assign) CGFloat

rotationAngleInRadians;

@end



helloWorldLabel is a label that we must create on the view of our view controller.



Then we will write the code that will rotate this label whenever the user attempts to

perform rotation gestures on the view that owns this label, in this case the view of

the view controller.

rotationGestureRecognizer is the instance of the rotation gesture recognizer that we



will later allocate and initialize.

rotationAngleInRadians is the value we will query as the exact rotation angle of



our label. Initially we will set this to zero. Since the rotation angles reported by a

rotation gesture recognizer are reset every time the rotation gesture is started again,

we can keep the value of the rotation gesture recognizer whenever it goes into the

UIGestureRecognizerStateEnded state. The next time the gesture is started, we will

add the previous value to the new value to get an overall rotation angle.

178 | Chapter 5: Implementing Gesture Recognizers



www.it-ebooks.info



Before we go any further, let’s go into the XIB file of our view controller, create

the corresponding Hello World label on its view, and link it to the IBOutlet that we

declared in the header file of our view controller:

1. Open the corresponding XIB file in Interface Builder. You can double-click on the

XIB file or press the Command + down arrow keys on the XIB file in Xcode.

2. In Interface Builder, use Tools→Library to bring up the Library pane.

3. Select the Label component from the Library pane, as shown in Figure 5-1, and

drag and drop it into the view of the view controller whose XIB file we have opened,

as shown in Figure 5-2.

4. Align the label in the center in the Attributes Inspector, which you can open using

Tools→Attributes Inspector in Interface Builder (Figure 5-3).

5. Select the label that you dropped on the view. Now open the Connections Inspector

in Interface Builder using Tools→Connections Inspector. Grab the New Reference

Outlet of the label in the Connections Inspector and drop it into the instance of

the label on the view, as shown in Figure 5-4.

Any component inheriting from UIView could be selected in the Library tab as our target

component. All UIView descendants have the transform property that we are going to

use in this section. For the sake of simplicity, I have chosen a label.



Figure 5-1. Selecting the Label component in the Library pane



5.2 Reacting to Rotation Gestures | 179



www.it-ebooks.info



Figure 5-2. Center-aligned label dropped on the view of a view controller with a navigation bar on top



Figure 5-3. Center-aligning the label using the Layout option in the Attributes Inspector pane in

Interface Builder



The size of the label does not matter much. Even the position of the label isn’t that

important, as we will only attempt to rotate the label around its center, no matter where

on our view the label is positioned. The only important thing to remember is that in

universal applications, the position of a label on a view controller used in different

180 | Chapter 5: Implementing Gesture Recognizers



www.it-ebooks.info



targets (devices) must be calculated dynamically using the size of its parent view. Otherwise, on different devices such as the iPad or the iPhone, it might appear in different

places on the screen.

Using the Layout option, we will center-align the contents of our label. The rotation

transformation that we will apply to this label rotates the label around its center, and

left-aligned or right-aligned labels whose actual frame is bigger than the minimum

frame that is required to hold their contents without truncation will appear to be rotating in an unnatural way and not on the center. If you are curious, just go ahead and

left- or right-align the contents of the label and see what happens.

After connecting the New Referencing Outlet of the label to the File’s Owner item as

shown in Figure 5-4, you will be presented with a dialog asking which outlet you want

to connect the component to, as shown in Figure 5-5.

Choose the helloWorldLabel outlet.



Figure 5-4. Connecting the referencing outlet of the label to its corresponding UILabel object in our

view controller



5.2 Reacting to Rotation Gestures | 181



www.it-ebooks.info



Figure 5-5. Available outlets in our view controller’s header file



Now we will implement our view controller in this way:

#import "RootViewController.h"

@implementation RootViewController

@synthesize rotationGestureRecognizer;

@synthesize helloWorldLabel;

@synthesize rotationAngleInRadians;

- (void) handleRotations:(UIRotationGestureRecognizer *)paramSender{

if (self.helloWorldLabel == nil){

return;

}

/* Take the previous rotation and add the current rotation to it */

self.helloWorldLabel.transform =

CGAffineTransformMakeRotation(self.rotationAngleInRadians +

paramSender.rotation);

/* At the end of the rotation, keep the angle for later use */

if (paramSender.state == UIGestureRecognizerStateEnded){

self.rotationAngleInRadians += paramSender.rotation;

}

}

- (void)viewDidLoad {

[super viewDidLoad];

/* Create the gesture recognizer */

UIRotationGestureRecognizer *rotationRecognizer =

[[UIRotationGestureRecognizer alloc]

initWithTarget:self

action:@selector(handleRotations:)];

self.rotationGestureRecognizer = rotationRecognizer;

[rotationRecognizer release];

/* Add it to our view */

[self.view addGestureRecognizer:self.rotationGestureRecognizer];

}

- (void) viewDidUnload{

[super viewDidUnload];



182 | Chapter 5: Implementing Gesture Recognizers



www.it-ebooks.info



}



self.helloWorldLabel = nil;

self.rotationGestureRecognizer = nil;



- (BOOL)shouldAutorotateToInterfaceOrientation

:(UIInterfaceOrientation)interfaceOrientation {

return YES;

}

- (void)dealloc {

[rotationGestureRecognizer release];

[helloWorldLabel release];

}



[super dealloc];



@end



The way a rotation gesture recognizer sends us the rotation angles is very interesting.

This gesture recognizer is continuous, which means it starts finding the angles as soon

as the user begins her rotation gesture, and sends updates to the handler method at

frequent intervals until the user finishes the gesture. Each message treats the starting

angle as zero and reports the difference between the messages’ starting point (which is

the angle where the previous message left off) and its ending point. Thus, the complete

effect of the gesture can be discovered only by summing the angles reported by the

different events. Clockwise movement produces a positive angular value, whereas

counterclockwise movement produces a negative value.

If you are using iPhone Simulator instead of a real device, you can still

simulate the rotation gesture by holding down the Option key in the

simulator. You will see two circles appearing on the simulator at the

same distance from the center of the screen, representing two fingers. If

you want to shift these fingers from the center to another location while

holding down the Alt key, press the Shift key and point to somewhere

else on the screen. Where you leave off your pointer will become the

new center for these two fingers.



Now we will simply assign this angle to the rotation angle of our label. But can you

imagine what will happen once the rotation is finished and another one starts? The

second rotation gesture’s angle will replace that of the first rotation in the rotation

value reported to our handler. For this reason, whenever a rotation gesture is finished,

we must keep the current rotation of our label. The value in each rotation gesture’s

angle must be added in turn, and we must assign the result to the label’s rotation

transformation as we saw before.

As we saw earlier, we used the CGAffineTransformMakeRotation function to create an

affine transformation. Functions in the iOS SDK that start with “CG” refer to the Core

5.2 Reacting to Rotation Gestures | 183



www.it-ebooks.info



Graphics framework. For programs that use Core Graphics to compile and link successfully, you must make sure the Core Graphics framework is added to the list of

frameworks. To do this, follow these steps:

1.

2.

3.

4.



Find and select your target output in Xcode, as shown in Figure 5-6.

Choose File→Get Info. Now you will see the Target Information page.

At the top of the Target Information page, choose the General tab.

At the bottom of the page, make sure Core Graphics is added to the Linked Libraries section. If it is not, click the + button and choose Core Graphics from the list.

Finally, click the Add button, as shown in Figure 5-7.



Figure 5-6. Finding and selecting our target in Xcode



You must add the required frameworks for each target individually even

if you have duplicated one target to create other targets. Adding a

framework to the Frameworks folder directly will add the frameworks

to the current target only.



Now that we are sure Core Graphics is added to our target, we can compile and run

our application.



184 | Chapter 5: Implementing Gesture Recognizers



www.it-ebooks.info



Figure 5-7. Adding the Core Graphics framework to our target



See Also

Recipe 5.6



5.3 Detecting Panning and Dragging Gestures

Problem

You want the users of your application to be able to move GUI elements around using

their fingers.



Solution

Use the UIPanGestureRecognizer class:

- (void)viewDidLoad {

[super viewDidLoad];

/* Let's first create a label */

CGRect labelFrame = CGRectMake(0.0f,

0.0f,

150.0f,

100.0f);



/*

/*

/*

/*



X */

Y */

Width */

Height */



UILabel *newLabel = [[UILabel alloc] initWithFrame:labelFrame];



5.3 Detecting Panning and Dragging Gestures | 185



www.it-ebooks.info



self.helloWorldLabel = newLabel;

[newLabel release];

self.helloWorldLabel.text = @"Hello World";

/* Contrasting colors to catch more attention */

self.helloWorldLabel.backgroundColor = [UIColor blackColor];

self.helloWorldLabel.textColor = [UIColor whiteColor];

/* Center align the text to make it look better */

self.helloWorldLabel.textAlignment = UITextAlignmentCenter;

/* Make sure to enable user interaction; otherwise, tap events

won't be caught on this label */

self.helloWorldLabel.userInteractionEnabled = YES;

/* And now make sure this label gets displayed on our view */

[self.view addSubview:self.helloWorldLabel];

/* Create the Pan Gesture Recognizer */

UIPanGestureRecognizer *newPanGestureRecognizer =

[[UIPanGestureRecognizer alloc]

initWithTarget:self

action:@selector(handlePanGestures:)];

self.panGestureRecognizer = newPanGestureRecognizer;

[newPanGestureRecognizer release];

/* At least and at most we need only one finger to activate

the pan gesture recognizer */

self.panGestureRecognizer.minimumNumberOfTouches = 1;

self.panGestureRecognizer.maximumNumberOfTouches = 1;

/* Add it to our view */

[self.helloWorldLabel addGestureRecognizer:self.panGestureRecognizer];

/* Get rid of the navigation bar for now as we don't need it */

self.navigationController.navigationBarHidden = YES;

}

- (void) viewDidUnload{

[super viewDidUnload];

self.panGestureRecognizer = nil;

self.helloWorldLabel = nil;

}



The pan gesture recognizer will call the handlePanGestures: method as its target method. This method is described in this recipe’s Discussion.



Discussion

The UIPanGestureRecognizer, as its name implies, can detect pan gestures. Pan gestures

are continuous movements of fingers on the screen; recall that swipe gestures were

186 | Chapter 5: Implementing Gesture Recognizers



www.it-ebooks.info



Xem Thêm
Tải bản đầy đủ (.pdf) (640 trang)

Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Tải bản đầy đủ ngay
×