Josiah Josiah - 3 years ago 191
Objective-C Question

How to properly use swipeWithEvent to navigate a webView, Obj-C

I want to implement the ability to navigate back and fourth in my webView by using the Event swipeWithEvent. However, I have no idea how I am suppose to use this.

I have one main webView, and two methods that navigate back and fourth. A big problem here is that I'm not exactly sure how to write this question. I just need to know how to recognize swipe gestures on my webView and call my two methods. Similar to what Safari, Google Chrome, and Mozilla Firefox do. Thanks.

I have implemented these methods which are suppose to allow me to swipe back and forward.

- (void)swipeWithEvent:(NSEvent *)event {
NSLog(@"Swipe With Event");
CGFloat x = [event deltaX];
//CGFloat y = [event deltaY];

if (x != 0) {
(x > 0) ? [self goBack:self] : [self goForward:self];

NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
return [defaults boolForKey:@"AppleEnableSwipeNavigateWithScrolls"];

- (void)beginGestureWithEvent:(NSEvent *)event
if (![self recognizeTwoFingerGestures])

NSSet *touches = [event touchesMatchingPhase:NSTouchPhaseAny inView:nil];

self.twoFingersTouches = [[NSMutableDictionary alloc] init];

for (NSTouch *touch in touches) {
[twoFingersTouches setObject:touch forKey:touch.identity];

- (void)endGestureWithEvent:(NSEvent *)event
if (!twoFingersTouches) return;

NSSet *touches = [event touchesMatchingPhase:NSTouchPhaseAny inView:nil];

// release twoFingersTouches early
NSMutableDictionary *beginTouches = [twoFingersTouches copy];
self.twoFingersTouches = nil;

NSMutableArray *magnitudes = [[NSMutableArray alloc] init];

for (NSTouch *touch in touches)
NSTouch *beginTouch = [beginTouches objectForKey:touch.identity];

if (!beginTouch) continue;

float magnitude = touch.normalizedPosition.x - beginTouch.normalizedPosition.x;
[magnitudes addObject:[NSNumber numberWithFloat:magnitude]];

// Need at least two points
if ([magnitudes count] < 2) return;

float sum = 0;

for (NSNumber *magnitude in magnitudes)
sum += [magnitude floatValue];

// Handle natural direction in Lion
BOOL naturalDirectionEnabled = [[[NSUserDefaults standardUserDefaults] valueForKey:@""] boolValue];

if (naturalDirectionEnabled)
sum *= -1;

// See if absolute sum is long enough to be considered a complete gesture
float absoluteSum = fabsf(sum);

if (absoluteSum < kSwipeMinimumLength) return;

// Handle the actual swipe
if (sum > 0)
[self goForward:self];
} else
[self goBack:self];


However, this code isn't doing anything. It doesn't appear to be getting called at all.

Answer Source

For modern OSes (Lion and newer), this is one of those "How do I do X with Y?" questions where the answer is "Don't use Y."

-swipeWithEvent: is used to implement 10.6-style trackpad swiping, where the content on the screen doesn't move with the swipe. Most Mac trackpads are not configured to allow this kind of swiping anymore; the "Swipe between pages" preference in Trackpad pref pane has to be set to "swipe with three fingers" for it to be available, and that's neither the default setting nor a common setting for users to change.

Lion-style "fluid swipes" instead come in as scroll events. The PictureSwiper sample project in your Xcode SDK is a good place to start, but as an overview, here's what you do:

If you only need to support 10.8+

Use an NSPageController in history stack mode.

If you need to support 10.7

  1. Seriously consider supporting only 10.8+, at least for this feature. Implementing it manually is a huge mess. Don't say I didn't warn you.

  2. Create a custom view that is a superview to whatever views you want to be swipeable.

  3. Override -wantsScrollEventsForSwipeTrackingOnAxis: to return YES for the appropriate axis. If you're doing Safari-style back/forward navigation, that's NSEventGestureAxisHorizontal.

  4. Take a deep breath; this one's a doozy.

  5. Override -scrollWheel: in your custom view. Your override should call -trackSwipeEventWithOptions:dampenAmountThresholdMin:max:usingHandler:. Roughly, the dampen amount threshold minimum is how many viewfuls of data the user can swipe to the left, and the maximum is how many they can swipe to the right. The handler is a block that's called repeatedly as the user swipes; it should:

    1. Place an NSImageView with a screenshot of the page you're going back/forward to behind your content view.
    2. Move the content view to match the user's movements. Note that the gestureAmount parameter is, like the dampen amount thresholds, a (fractional and possibly negative) number of items; you have to multiply it by the view width to correctly position the content view.
    3. If the gesture phase is NSEventPhaseEnded, evaluate the gestureAmount to determine if the user completed the gesture. If they didn't, animate the content view back into place; if they did, put the content view back in place with no animation and update it to match the screenshot.

As you can see, actually implementing the handler is very involved, and I haven't even described all of the specifics. Even with all of these details, a highly skilled programmer will probably have to spend a few days getting this just right. The PictureSwiper sample in the 10.7 SDK is a good place to start. (The 10.8 version of PictureSwiper uses NSPageController. Just like you ought to do.)

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download