4

Has anyone been able to implement a successful swipe gesture on a UITableView? By default this is not possible due to the scrolling nature of the control. I've tried subclassing UITextView and implementing the swipe function in the instance methods, but no dice.

My UITextView has scrolling disabled - Unless there is another way to implement multiline text?

[Edit] What I should say is input multiline text[/Edit]

mootymoots
  • 4,545
  • 9
  • 46
  • 74

6 Answers6

3

Here is a subclass of a UITextView that will detect a swipes gesture...

Is this what you are looking for?

#import <UIKit/UIKit.h>

#define kMinimumGestureLength   25
#define kMaximumVariance        5

@interface SwipeableTextView : UITextView {
    CGPoint gestureStartPoint;
}

@end

@implementation SwipeableTextView

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesBegan:touches withEvent:event];

    UITouch *touch =[touches anyObject];
    gestureStartPoint = [touch locationInView:self];

}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesMoved:touches withEvent:event];

    UITouch *touch = [touches anyObject];
    CGPoint currentPosition = [touch locationInView:self];

    CGFloat deltaX = fabsf(gestureStartPoint.x - currentPosition.x);
    CGFloat deltaY = fabsf(gestureStartPoint.y - currentPosition.y);

    if (deltaX >= kMinimumGestureLength && deltaY <= kMaximumVariance) {
        NSLog(@"Horizontal swipe detected");
    }

}

@end
Ross
  • 14,266
  • 12
  • 60
  • 91
  • Thanks - I will try this today at some point and let you know how it goes. – mootymoots Jan 13 '10 at 09:50
  • I'm afraid this didn't work. I've added it as a subclass, changed the class to my new subclass in Interface Builder, and also updated the class in my main view controller to the subclass, but no swipe is detected :-( – mootymoots Jan 14 '10 at 16:21
3

An even better solution, I have found, is to simply pass touches back to the superview:

@interface SwipeableTextView : UITextView {
}

@end

@implementation SwipeableTextView

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesBegan:touches withEvent:event];

    [self.superview touchesBegan:touches withEvent:event];

}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesMoved:touches withEvent:event];

    [self.superview touchesMoved:touches withEvent:event];
}

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesEnded:touches withEvent:event];

    [self.superview touchesEnded:touches withEvent:event];
} 

@end
Jason
  • 14,517
  • 25
  • 92
  • 153
2

Add a transparent UIView on top of the UITextView and use it to handle the swipe, and send the touchesBegan/Moved/Ended/Canceled: messages to the text view to preserve normal interaction.

kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005
2

I took Ross's code and added a few things that helped me. In particular, this code won't respond to the swipe until it stops. It also prevents a swipe from reversing direction partway through.

#import <UIKit/UIKit.h>

#define kMinimumGestureLength   25
#define kMaximumVariance        5

typedef enum swipeDirection {
    kSwipeNone,
    kSwipeLeft,
    kSwipeRight
} tSwipeDirection;

@interface SwipeableTextView : UITextView {
    CGPoint gestureStartPoint;
    tSwipeDirection swipeDirection;
}

@end

@implementation SwipeableTextView

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesBegan:touches withEvent:event];

    swipeDirection = kSwipeNone;
    UITouch *touch =[touches anyObject];
    gestureStartPoint = [touch locationInView:self];

}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesMoved:touches withEvent:event];

    UITouch *touch = [touches anyObject];
    CGPoint currentPosition = [touch locationInView:self];

    CGFloat deltaX = fabsf(gestureStartPoint.x - currentPosition.x);
    CGFloat deltaY = fabsf(gestureStartPoint.y - currentPosition.y);

    // Check if we already started a swipe in a particular direction
    // Don't let the user reverse once they get going
    if (deltaX >= kMinimumGestureLength && deltaY <= kMaximumVariance &&
        swipeDirection == kSwipeNone) {
        if (gestureStartPoint.x < currentPosition.x) {
            swipeDirection = kSwipeRight;
        }
        else {
            swipeDirection = kSwipeLeft;
        }
    }
}

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    if (swipeDirection == kSwipeRight) {
        NSLog(@"Swipe right");
    }
    else if (swipeDirection == kSwipeLeft) {
        NSLog(@"Swipe left");
    }
    [super touchesEnded:touches withEvent:event];
} 

@end
Cliff McC
  • 51
  • 3
1

Usually you implement the touch responding events in a UITableViewCell, which can recognize the swipe and do something. UITableViews inherit from UIScrollView which does not like having touch events overridden.

Kendall Helmstetter Gelner
  • 74,769
  • 26
  • 128
  • 150
  • Hi, can you explain more on why UIScrollView doesn't like having its touch events overridden? – Ross Jan 12 '10 at 14:25
  • 1
    Not really much, other than it does a lot of complex work with touch events and so when it doesn't get everything it can't figure out what is going on... sorry I can't add more detail, I just know from experience it doesn't work well. – Kendall Helmstetter Gelner Jan 12 '10 at 17:09
0

You could also use a two finger swipe. When I get home I can elaborate with some code but that was what I have used

Jab
  • 26,853
  • 21
  • 75
  • 114