14

我有一个关于跟踪 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();
}

谢谢!

4

3 回答 3

8

It appears the "proper" way to track multiple touches is by the pointer value of the UITouch event.

You can find more details in the "Handling a Complex Multi-Touch Sequence" section of this Apple Developer Documentation

于 2010-03-28T07:18:08.340 回答
7

要解决您的问题,请废弃您的“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 在跟踪整个手指时会对其进行变异。改变的触摸属性是触摸的阶段、它在视图中的位置、它的先前位置和它的时间戳。事件处理代码评估这些属性以确定如何响应事件。

于 2009-05-27T04:22:36.057 回答
0

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

在你的-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 对象中(或使用不同类型的数组)。

于 2009-05-26T23:40:12.807 回答