如何忽略多点触控序列中的某些 UITouch 点 [英] How to ignore certain UITouch Points in multitouch sequence

查看:19
本文介绍了如何忽略多点触控序列中的某些 UITouch 点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为 ipad 开发绘图应用程序,我正在提供全屏绘图.因此,就像我们现在所有人一样,用户可能会用他的手腕支撑或将手放在屏幕上来书写.所以我的目标是让用户用他的手腕/手支撑自由书写.

I am working on a drawing app for ipad, I am providing full screen for drawing. So as we all now, user might write with his wrist support or by resting his hand on the screen. So my aim is to allow the user to write freely with his wrist/hand support.

但应用应该只检测手指的绘制,或者忽略/拒绝手腕和手部的触摸并将它们删除

But the app should only detect finger drawing, or ignore/reject wrist and hand touches and delete them

我开始研究它,我创建了一个启用多点触控的示例项目.

I started working on it , I created a sample project with multitouch enabled.

下面是我的代码

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    mouseSwiped = NO;

    for (UITouch *touch in touches)
    {
        NSString *key = [NSString stringWithFormat:@"%d", (int) touch];
        lastPoint = [touch locationInView:self.view];

        [touchPaths setObject:[NSValue valueWithCGPoint:lastPoint] forKey:key];
    }

}


- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{    
    mouseSwiped = YES;
    CGPoint lastPoint3;

    for (UITouch *touch in touches)
    {
        NSString *key = [NSString stringWithFormat:@"%d", (int) touch];

        lastPoint = [[touchPaths objectForKey:key] CGPointValue];


        currentPoint1 = [touch locationInView:self.view];

        NSLog(@"Y:%f",currentPoint1.y);


        UIGraphicsBeginImageContext(self.view.frame.size);
        [self.tempDrawImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
        CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
        CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brush );
        CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), red, green, blue, 1.0);
        CGContextSetBlendMode(UIGraphicsGetCurrentContext(),kCGBlendModeNormal);
        CGContextBeginPath(UIGraphicsGetCurrentContext());
        CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
        CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint1.x, currentPoint1.y);

        CGContextStrokePath(UIGraphicsGetCurrentContext());
        self.tempDrawImage.image = UIGraphicsGetImageFromCurrentImageContext();
        [self.tempDrawImage setAlpha:opacity];
        UIGraphicsEndImageContext();

       [touchPaths setObject:[NSValue valueWithCGPoint:currentPoint1] forKey:key];
    }
}

所以这适用于任何数量的触摸,但我不明白如何在绘图时拒绝那些手掌/手触摸,只绘制用户用手指/手写笔绘制的内容.

So this works fine with any number of touches, But I am not understanding how can I reject those palm/hand touches while drawing and only draw, what user draws with his finger/ stylus.

现在如果我画画,我得到了这个东西,下面是图像

Presently if I draw, I get this thing, below is the image

这里我是用手撑着画的,你可以在下面看到你好",他们发生了一些奇怪的画图.我怎样才能拒绝这些触摸并删除它们,只画你好

谢谢

兰吉特

推荐答案

一种解决方案是将最上面的点击存储在 touchesBegan 中,并且只绘制这个.

One solution is to store the topmost tap in touchesBegan and only draw this one.

正如您所指出的,您不应该保留 UITouch 实例,因此我建议改用弱引用.

As you have pointed out, you are not supposed to retain the UITouch instance, so I recommend using a weak reference instead.

这只会绘制一次触摸.如果您希望绘制多个手指的触摸,则需要另一种过滤手的方法(例如,许多绘图应用程序都有用户设置来告诉应用程序手的姿势,但这当然更复杂).

This will only draw a single touch. If you wish to draw the touches of multiple fingers, you need another way of filtering out the hand (many drawing apps have user settings for telling the app the pose of the hand, for example, but this is of course more complicated).

这里有一个关于如何做的想法:

Here is an idea on how to do it:

#import <QuartzCore/QuartzCore.h>

@interface TViewController () {
    // We store a weak reference to the current touch that is tracked
    // for drawing.
    __weak UITouch* drawingTouch;
    // This is the previous point we drawed to, or the first point the user tapped.
    CGPoint touchStartPoint;
}
@end
@interface _TDrawView : UIView {
@public
    CGLayerRef persistentLayer, tempLayer;
}
-(void)commitDrawing;
-(void)discardDrawing;
@end

@implementation TViewController

- (void) loadView
{
    self.view = [[_TDrawView alloc] initWithFrame:[UIScreen mainScreen].bounds];
    self.view.opaque = YES;
    self.view.multipleTouchEnabled = YES;
    self.view.backgroundColor = [UIColor whiteColor];
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    // Start with what we currently have
    UITouch* topmostTouch = self->drawingTouch;
    // Find the top-most touch
    for (UITouch *touch in touches) {
        CGPoint lastPoint = [touch locationInView:self.view];
        if(!topmostTouch || [topmostTouch locationInView:self.view].y > lastPoint.y) {
            topmostTouch = touch;
            touchStartPoint = lastPoint;
        }
    }
    // A new finger became the drawing finger, discard any previous 
    // strokes since last touchesEnded
    if(self->drawingTouch != nil && self->drawingTouch != topmostTouch) {
        [(_TDrawView*)self.view discardDrawing];
    }
    self->drawingTouch = topmostTouch;
}

- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    // Always commit the current stroke to the persistent layer if the user
    // releases a finger. This could need some tweaking for optimal user experience.
    self->drawingTouch = nil;
    [(_TDrawView*)self.view commitDrawing];
    [self.view setNeedsDisplay];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    const CGFloat red=0, green=0, blue=0, brush=1;
    for (UITouch *touch in touches) {
        // Find the touch that we track for drawing
        if(touch == self->drawingTouch) {
            CGPoint currentPoint = [touch locationInView:self.view];

            // Draw stroke first in temporary layer
            CGContextRef ctx = CGLayerGetContext(((_TDrawView*)self.view)->tempLayer);
            CGContextSetLineCap(ctx, kCGLineCapRound);
            CGContextSetLineWidth(ctx, brush );
            CGContextSetRGBStrokeColor(ctx, red, green, blue, 1.0);
            CGContextSetBlendMode(ctx,kCGBlendModeNormal);
            CGContextBeginPath(ctx);
            CGContextMoveToPoint(ctx, touchStartPoint.x, touchStartPoint.y);
            CGContextAddLineToPoint(ctx, currentPoint.x, currentPoint.y);
            CGContextStrokePath(ctx);
            // Update the points so that the next line segment is drawn from where
            // we left off
            touchStartPoint = currentPoint;
            // repaint the layer
            [self.view setNeedsDisplay];
        }
    }
}

@end

@implementation _TDrawView

- (void) finalize {
    if(persistentLayer) CGLayerRelease(persistentLayer);
    if(tempLayer) CGLayerRelease(tempLayer);
}

- (void) drawRect:(CGRect)rect {
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    if(!persistentLayer) persistentLayer = CGLayerCreateWithContext(ctx, self.bounds.size, nil);
    if(!tempLayer) tempLayer = CGLayerCreateWithContext(ctx, self.bounds.size, nil);

    // Draw the persistant drawing
    CGContextDrawLayerAtPoint(ctx, CGPointMake(0, 0), persistentLayer);
    // Overlay with the temporary drawing
    CGContextDrawLayerAtPoint(ctx, CGPointMake(0, 0), tempLayer);
}

- (void)commitDrawing {
    // Persist the temporary drawing
    CGContextRef ctx = CGLayerGetContext(persistentLayer);
    CGContextDrawLayerAtPoint(ctx, CGPointMake(0, 0), tempLayer);
    [self discardDrawing];
}
- (void)discardDrawing {
    // Clears the temporary layer
    CGContextRef ctx = CGLayerGetContext(tempLayer);
    CGContextClearRect(ctx, self.bounds);
    CGContextFlush(ctx);
}
@end

我添加了这样的逻辑,即如果检测到新的触摸,如果当前有任何使用更高 y 值绘制的笔画,则会将其删除,正如我们在评论中讨论的那样.

I added the logic that if a new touch is detected, if there is currently any stroke being drawn with a higher y-value, it is removed, as we discussed in the comments.

叠加是通过绘制两个CGLayer来完成的.这段代码可以针对性能进行很多优化,它应该更多地被视为一个说明而不是生产就绪代码.

The overlaying is done by painting two CGLayers. This code could be optimized a lot for performance, it should be looked at more as an illustration than production-ready code.

这篇关于如何忽略多点触控序列中的某些 UITouch 点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆