【问题标题】:iPhone: Tracking/Identifying individual touchesiPhone:跟踪/识别个人触摸
【发布时间】:2010-10-29 02:59:06
【问题描述】:

我有一个关于在 iPhone 上跟踪触摸的快速问题,我似乎无法就此得出结论,因此非常感谢任何建议/想法:

我希望能够跟踪和识别 iPhone 上的触摸,即。基本上每次触摸都有一个起始位置和一个当前/移动位置。触摸存储在 std::vector 中,一旦结束,它们应从容器中删除。一旦他们移动,他们的位置就会更新,但我仍然想跟踪他们最初开始的位置(手势识别)。

我正在从 [event allTouches] 获取触摸,事情是,NSSet 未排序,我似乎无法识别已存储在 std::vector 中的触摸并引用 NSSet 中的触摸(所以我知道哪些已经结束并且应该被删除,或者已经被移动等等)

这是我的代码,当然,只需一根手指在触摸屏上即可完美运行,但如果使用多根手指,我确实会得到不可预知的结果...

    - (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
{
    [self handleTouches:[event allTouches]];
}

- (void) touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event
{
    [self handleTouches:[event allTouches]];
}

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

- (void) touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event
{
    [self handleTouches:[event allTouches]];
}

- (void) handleTouches:(NSSet*)allTouches
{   
    for(int i = 0; i < (int)[allTouches count]; ++i)
    {
        UITouch* touch = [[allTouches allObjects] objectAtIndex:i];
        NSTimeInterval timestamp = [touch timestamp];

        CGPoint currentLocation = [touch locationInView:self];
        CGPoint previousLocation = [touch previousLocationInView:self];

        if([touch phase] == UITouchPhaseBegan)
        {
            Finger finger;
            finger.start.x = currentLocation.x;
            finger.start.y = currentLocation.y;
            finger.end = finger.start;
            finger.hasMoved = false;
            finger.hasEnded = false;

            touchScreen->AddFinger(finger);
        }
        else if([touch phase] == UITouchPhaseEnded || [touch phase] == UITouchPhaseCancelled)
        {
            Finger& finger = touchScreen->GetFingerHandle(i);

            finger.hasEnded = true;
        }
        else if([touch phase] == UITouchPhaseMoved)
        {
            Finger& finger = touchScreen->GetFingerHandle(i);

            finger.end.x = currentLocation.x;
            finger.end.y = currentLocation.y;
            finger.hasMoved = true;
        }
    }

    touchScreen->RemoveEnded();
}

谢谢!

【问题讨论】:

    标签: iphone cocoa-touch uikit multi-touch


    【解决方案1】:

    您应该能够通过存储所有触摸的先前位置,然后在检测到新触摸时比较这些先前位置来正确整理您的触摸。

    在你的 -handleTouches 方法中,你可以在你的 for 循环中加入这样的东西:

    // ..existing code..
    CGPoint previousLocation = [touch previousLocationInView:self];
    
    // Loop through previous touches
    for (int j = 0; j < [previousTouchLocationArray count]; j++) {
      if (previousLocation == [previousTouchLocationArray objectAtIndex:j]) {
        // Current touch matches - retrieve from finger handle j and update position
      }
    }
    
    // If touch was not found, create a new Finger and associated entry 
    

    显然,您需要做一些工作才能将其集成到您的代码中,但我很确定您可以使用这个想法来正确识别在屏幕上移动的触摸。此外,我刚刚意识到 CGPoint 不能很好地融入 NSArray - 您需要将它们包装在 NSValue 对象中(或使用不同类型的数组)。

    【讨论】:

    • 好主意。但是,出于某种原因,这对我不起作用。似乎职位有时会关闭。当我渲染到 OpenGL 上下文(我正在开发游戏)时,这可能是由于性能下降所致。也许触摸事件确实会被丢弃,并且之前的位置不再对应于存储的位置?不过,谢谢!
    • 这也给我带来了麻烦。尤其是当您在屏幕上移动很多手指时。有时您会得到一个与以前的任何位置都不匹配的位置。
    【解决方案2】:

    要解决您的问题,请废弃您的“handleTouches”方法。您在 handleTouches 方法中做的第一件事是在 touchPhase 上打开它,但这已经给您了。如果您在 touchesBegan 中收到触摸,您就知道触摸在 UITouchPhaseBegan 中。通过将四种触摸方法中的触摸汇集到一种方法中,您就违背了拥有四种委托方法的目的。

    在每种方法中,Apple 都为您提供了处理当前触摸的不同阶段的机会。

    第二件事是你不需要搜索当前触摸的事件,它作为参数给你:touches。

    一个事件由多组触摸组成。为方便起见,尽管它也可以在事件中找到,但您会得到当前的触摸。

    因此,在 touchesBegan 中,您开始跟踪触摸。

        - (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event{
    
    
            NSString *startPoint = NSStringFromCGPoint([[touches anyObject] locationInView:self]);  
    
            NSDictionary * touchData = [NSDictionary dictionaryWithObjectsandKeys: startPoint, @"location", touches, @"touch"]
    
            [startingLocations addObject:touchData];
    
            }
    

    我正在使用一个字典数组来保存我的触摸数据。

    尝试分离您的代码并将其移动到适当的触摸方法中。作为指导,Apple 提供了几个示例项目,这些项目专注于触摸并向您展示如何设置这些方法。

    请记住,这些方法将在每个阶段的每次触摸时自动调用,您无需循环通过事件来了解发生了什么。

    指向每组触摸的指针保持不变,只是数据发生变化。

    另外,我会阅读有关事件处理的 iPhone OS 编程指南部分,该部分对我上面所说的内容进行了更深入的介绍,其中有几个图表解释了随着时间的推移触摸与事件的关系。

    摘录:

    在 iPhone OS 中,一个 UITouch 对象 代表一个触摸,一个 UIEvent 对象代表一个事件。一个事件 对象包含所有触摸对象 当前的多点触控序列和 可以提供特定的触摸对象 视图或窗口(见图 3-2)。一种 触摸对象对于给定的是持久的 序列中的手指,以及 UIKit 在跟踪手指时对其进行变异 贯穿其中。触控属性 这种变化是 触摸,它在视图中的位置,它的 以前的位置及其时间戳。 事件处理代码评估这些 属性来确定如何响应 参加活动。

    【讨论】:

    • 我同意你的看法。我将代码拆分为适当的方法。但是,我的问题是我需要在 Obj-C 和 C++ 之间创建一个链接,而我的游戏架构需要轮询输入,而不是在触发事件后处理。这就是我将触摸存储在 STL 向量中的原因。无论如何,您关于 UITouch 对象随时间持续存在的信息有很大帮助。现在,我使用对象的地址作为唯一标识触摸的键。奇迹般有效。谢谢。
    • “如果您在 touchesBegan 中收到触摸,您知道触摸在 UITouchPhaseBegan 中” - 真的吗?这对我来说听起来不对 - 从 Apple 的文档中,他们似乎说相反:使用 MultiTouch,来自 touchesBegan 的触摸可以在任何阶段。
    • @Adam 你可能误读了。尽管事件中包含的触摸可能处于另一个阶段。 “touches”参数中的所有触摸都保证在指定的阶段。来自事件处理指南:“如果出于某种原因,您对当前多点触控序列中的触摸感兴趣,这些触摸自上一个阶段以来没有改变,或者处于传入集合中的那些以外的阶段,您可以请求它们来自传入的 UIEvent 对象。”
    • @Corey - 谢谢。我误解了一段时间:(。根据您引用的文档对其进行了测试以检查,它的行为与描述的一样。
    【解决方案3】:

    看来跟踪多次触摸的“正确”方法是通过 UITouch 事件的指针值。

    您可以在本文的“处理复杂的多点触控序列”部分找到更多详细信息 Apple Developer Documentation

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-31
    • 2013-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-14
    相关资源
    最近更新 更多