Cocoa and Objective-C: Handling Events

0
109
7 min read

 

Cocoa and Objective-C Cookbook

Cocoa and Objective-C Cookbook

Move beyond basic Cocoa development using over 70 simple and effective recipes for Mac OS X development

        Read more about this book      

(For more resources related to this subject, see here.)

Some recipes in this article require Mac OS X Snow Leopard 10.6.

The Trackpad preferences allow you to easily adjust many gestures that will used in the following recipes.

To make sure that your trackpad is recognizing gestures, make sure that you have set the correct preferences to enable gesture support under the Trackpad System Preference.

Interpreting the pinch gesture

The pinch gesture is a gesture normally used for the zooming of a view or for changing the font size of text. In this recipe, we will create a custom view that handles the pinch gesture to resize a custom view.

Getting ready

In Xcode, create a new Cocoa Application and name it Pinch.

How to do it…

  1. In the Xcode project, right-click on the Classes folder and choose Add…, then choose New File… Under the MacOS X section, select Cocoa Class, then select Objective-C class. Finally, choose NSView in the Subclass of popup. Name the new file MyView.m
  2. Double-click on the MainMenu.xib file in the Xcode project. From Interface Builders Library palette, drag a Custom View into the application window.
  3. From Interface Builders Inspector’s palette, select the Identity tab and set the Class popup to MyView.
  4. Choose Save from the File menu to save the changes that you have made.
  5. In Xcode, Add the following code in the drawRect: method of the MyView class implementation:

    NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:
    [self bounds] xRadius:8.0 yRadius:8.0];
    [path setClip];

    [[NSColor whiteColor] setFill];
    [NSBezierPath fillRect:[self bounds]];

    [path setLineWidth:3.0];

    [[NSColor grayColor] setStroke];
    [path stroke];

  6. Next, we need to add the code to handle the pinch gesture. Add the following method to the MyView class implementation:

    - (void)magnifyWithEvent:(NSEvent *)event {

    NSSize size = [self frame].size;
    size.height = size.height * ([event magnification] + 1.0);
    size.width = size.width * ([event magnification] + 1.0);

    [self setFrameSize:size];
    }

  7. Choose Build and Run from Xcode’s toolbar to run the application.

How it works…

In our drawRect: method, we use Cocoa to draw a simple rounded rectangle with a three point wide gray stroke. Next, we implement the magnifyWithEvent: method. Because NSView inherits from NSResponder, we can override the magnifyWithEvent: method from the NSResponder class. When the user starts a pinch gesture, and the magnifyWithEvent: method is called, the NSEvent passed to us in the magnifyWithEvent: method which contains a magnification factor we can use to determine how much to scale our view. First, we get the current size of our view. We add one to the magnification factor and multiply by the frame’s width and height to scale the view. Finally, we set the frame’s new size.

There’s more…

You will notice when running the sample code that our view resizes with the lower-left corner of our custom view remaining in a constant position. In order to make our view zoom in and out from the center, change the magnifyWithEvent: method’s code to the following:

NSSize size = [self frame].size;
NSSize originalSize = size;
size.height = size.height * ([event magnification] + 1.0);
size.width = size.width * ([event magnification] + 1.0);

[self setFrameSize:size];

CGFloat deltaX = (originalSize.width - size.width) / 2;
CGFloat deltaY = (originalSize.height - size.height) / 2;

NSPoint origin = self.frame.origin;
origin.x = origin.x + deltaX;
origin.y = origin.y + deltaY;
[self setFrameOrigin:origin];

Basically, what we have done is moved our custom view’s origin by the difference between the original size and the new size.

Interpreting the swipe gesture

The swipe gesture is detected when three or more fingers move across the trackpad. This gesture is often used to page through a series of images. In this recipe, we will create a custom view that interprets the swipe gesture in four different directions and displays the direction of the swipe in our custom view:

Cocoa and Objective-C: Handling Events

Getting ready

In Xcode, create a new Cocoa Application and name it Swipe.

How to do it…

  1. In the Xcode project, right-click on the Classes folder and choose Add…, then choose New File… Under the MacOS X section, select Cocoa Class, then select Objective-C class. Finally, choose NSView in the Subclass of popup. Name the new file MyView.m
  2. Double-click on the MainMenu.xib file in the Xcode project. From Interface Builders Library palette, drag a Custom View into the application window.
  3. From Interface Builders Inspector’s palette, select the Identity tab and set the Class popup to MyView.
  4. Choose Save from the File menu to save the changes that you have made.
  5. In Xcode, open the MyView.h file and add the direction variable to the class interface:

    NSString *direction;

  6. Open the MyView.m file and add the following code in the drawRect: method of the MyView class implementation:

    NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:
    [self bounds] xRadius:8.0 yRadius:8.0];
    [path setClip];

    [[NSColor whiteColor] setFill];
    [NSBezierPath fillRect:[self bounds]];
    [path setLineWidth:3.0];

    [[NSColor grayColor] setStroke];
    [path stroke];

    if (direction == nil) {
    direction = @"";
    }

    NSAttributedString *string = [[[NSAttributedString alloc] initWithString:direction] autorelease];
    NSPoint point = NSMakePoint(([self bounds].size.width / 2) -
    ([string size].width / 2), ([self bounds].size.height / 2) -
    ([string size].height / 2));
    [string drawAtPoint:point];

  7. Add the following code to handle the swipe gesture:

    - (void)swipeWithEvent:(NSEvent *)event {
    if ([event deltaX] > 0) {
    direction = @"Left";
    } else if ([event deltaX] < 0) {
    direction = @"Right";
    } else if ([event deltaY] > 0) {
    direction = @"Up";
    } else if ([event deltaY] < 0){
    direction = @"Down";
    }
    [self setNeedsDisplay:YES];
    }

  8. In Xcode, choose Build and Run from the toolbar to run the application.

How it works…

As we did in the other recipes in this article, we draw a simple rounded rectangle in the drawRect: method of the view. However, we will also be drawing a string denoting the direction of the swipe in the middle of our view.

In order to handle the swipe gesture, we override the swipeWithEvent: method from the NSResponder class which NSView inherits. By inspecting the values of deltaX and deltaY of the NSEvent passed into the swipeWithEvent: method, we can determine the direction of the swipe. We set the direction string with the direction of the swipe so we can draw it in the drawRect: method. Finally, we call setNeedsDisplay:YES to force our view to redraw itself.

There’s more…

You might have noticed that we do not need to override the acceptsFirstResponder: method in our view in order to handle the gesture events. When the mouse is located within our view, we automatically receive the gesture events. All we need to do is implement the methods for the gestures we are interested in.

Interpreting the rotate gesture

The rotate gesture can be used in any number of ways in a custom view. From rotating the view itself or simulating a rotating dial in a custom control. This recipe will show you how to implement the rotate gesture to rotate a custom view. Using your thumb and index finger, you will be able to rotate the custom view around its center:

Cocoa and Objective-C: Handling Events

Getting ready

In Xcode, create a new Cocoa Application and name it Rotate.

How to do it…

  1. In the Xcode project, right-click on the Classes folder and choose Add…, then choose New File… Under the MacOS X section, select Cocoa Class, then select Objective-C class. Finally, choose NSView in the Subclass of popup. Name the new file MyView.m.
  2. Double-click on the MainMenu.xib file in the Xcode project. From Interface Builders Library palette, drag a Custom View into the application window.
  3. From Interface Builders Inspector’s palette, select the Identity tab and set the Class popup to MyView.
  4. Choose Save from the File menu to save the changes that you have made.
  5. In Xcode, add the following code in the drawRect: method of the MyView class implementation:

    NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:
    [self bounds] xRadius:8.0 yRadius:8.0];
    [path setClip];

    [[NSColor whiteColor] setFill];
    [NSBezierPath fillRect:[self bounds]];

    [path setLineWidth:3.0];

    [[NSColor grayColor] setStroke];
    [path stroke];

  6. Next we need to add the code to handle the rotate gesture. Add the following method to the MyView class implementation:

    - (void)rotateWithEvent:(NSEvent *)event {
    CGFloat currentRotation = [self frameCenterRotation];
    [self setFrameCenterRotation:(currentRotation + [event
    rotation])];
    }

  7. Choose Build and Run from Xcode’s toolbar to test the application.

How it works…

As we did in the previous recipe, we will create a simple rounded rectangle with a three-point stroke to represent our custom view.

Our custom view overrides the rotateWithEvent: method from NSResponder to handle the rotation gesture. The rotation property of the NSEvent passed to us in the rotateWithEvent: contains the change in rotation from the last time the rotateWithEvent: method was called. We simply add this value to our view’s frameCenterRotation value to get the new rotation.

There’s more…

The value returned from NSEvent‘s rotation will be negative when the rotation is clockwise and positive when the rotation is counter-clockwise.

LEAVE A REPLY

Please enter your comment!
Please enter your name here