views:

180

answers:

1

I'm trying to figure out the best way to handle pinch gestures in a UITextView. Currently I've been trying to handle it all in the UITextView, but I'm getting inconsistant results. It seems that it can catch my touches in the touches began method, but it doesn't always get caught in the touches moved method.

Would it be better to handle the touches in a View, and have the UITextView pass on the multitouch events? Would it be better to do something tricky like placing the UITextView in a scrollview?

At this point all I'd like to do is adjust the font size on a multitouch pinch or expand, which I can get to work, but it isn't consistant and I think I've managed to just confuse the UITextView more than actually get results.

My control is a subclass of UITextView and implements UITextViewDelegate:

#import "MyUITextView.h"
@implementation MyUITextView

/* skipping unimportant code */


-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    if([touches count] == 2)
    {
        NSLog(@"two touches");
        UITouch *first = [[touches allObjects] objectAtIndex:0];
        UITouch *second = [[touches allObjects] objectAtIndex:1];
        initialDistance = [self distanceBetweenTwoPoints:[first locationInView:self] toPoint:[second locationInView:self]];

     }
}

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"touches moved");
    if([touches count] == 2)
    {
        self.scrollEnabled = NO;
        UITouch *first  = [[touches allObjects] objectAtIndex:0];
        UITouch *second = [[touches allObjects] objectAtIndex:1];
        CGFloat currentDistance = [self distanceBetweenTwoPoints:[first locationInView:self] toPoint:[second locationInView:self]];
        if(initialDistance == 0)
            initialDistance = currentDistance;
        else if(currentDistance > initialDistance)
        {
            NSLog(@"zoom in");
            self.scrollEnabled = YES;
            self.font = [UIFont fontWithName:[self.font fontName] size:[self.font pointSize] + 1.0f];
            self.text = self.text;
        }
        else if(currentDistance < initialDistance)
        {
            NSLog(@"zoom out");
            self.scrollEnabled = YES;
            self.font = [UIFont fontWithName:[self.font fontName] size:[self.font pointSize] = 1.0f];
            self.text = self.text;
        }
    }    
}

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"touches ended.");
    initialDistance = 0;
    [super touchesEnded:touches withEvent:event];

}

-(CGFloat)distanceBetweenTwoPoints:(CGPoint)fromPoint toPoint:(CGPoint)toPoint
{
    float x = toPoint.x - fromPoint.x;
    float y = toPoint.y - fromPoint.y;
    return sqrt(x*x + y*y);

}

-(BOOL)canBecomeFirstResponder
{   return NO; }

Basically I've tried to disable the scrolling when I have two touches on the screen, and then re-enable it when I was done. Also, disabled the ability to become first responder so that I wouldn't have to be fighting with the copy and paste menu. If there is a better way to do this by allowing for the copy and paste menu when using a single touch I'm all ears. I think I'm basically working with a more advanced example for my first entry into this gesture business.

Also, since the control is handling all its own stuff, I didn't think it needed to pass on the touch events, since it is handling them itself. Am I wrong?

Finally, this UITextView of mine is created programatically and placed in a UINavigationControl. I don't know if that makes a difference or not.

A: 

I think I would start by fully logging all touches and all events. Make sure to log the view property of the touches.

You can also subclass UIWindow to create a diagnostic class that will log every touch in the app. This can be very useful for seeing exactly where and when touches are actually occurring. You might find that the touches are being routed to different views than you expect.

As noted in the comments to the OP, touchesMoved: can be called by just one touch of a multitouch gesture moving. So if you start a two touch gesture like a pinch but only move one finger, you only get one touch in touchesMoved:. For example, people often perform a pinch by placing down their thumb and forefinger and then moving the forefinger only. (Even if they move both, the forefinger will always move over a longer distance than the thumb because it is longer.)

TechZen