IPhone: отслеживание/идентификация отдельных штрихов
У меня есть быстрый вопрос касательно отслеживания касаний 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();
}
Спасибо!
Ответы
Ответ 1
Чтобы устранить проблему, замените метод "handleTouches". Первое, что вы делаете в методе handleTouches, - это переключить его на touchPhase, но это уже дано вам. Если вы получаете прикосновение в touchBegan, вы знаете, что это касается UITouchPhaseBegan. Направляя касание четырех методов касания к одному методу, вы побеждаете цель иметь четыре метода делегата.
В каждом из этих методов Apple дает вам возможность работать с другой фазой текущего касания.
Во-вторых, вам не нужно искать событие для текущего касания, оно дается вам как параметр: касается.
Событие состоит из наборов штрихов. Для приведения в исполнение вам даются текущие штрихи, даже если они также могут быть найдены в рамках события.
Итак, в touchBegan, вы начинаете отслеживать прикосновение.
- (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 мутирует его, когда он отслеживает палец во всем этом. Сенсорные атрибуты это изменение является фазой касание, его расположение в представлении, его предыдущее местоположение и его временную метку. Код обработки событий оценивает эти атрибуты, чтобы определить, как реагировать к событию.
Ответ 2
Кажется, что "правильный" способ отслеживать несколько касаний - значением указателя события UITouch.
Более подробную информацию вы найдете в разделе "Обработка сложной последовательности Multi-Touch Sequence" этого раздела
Документация разработчика Apple
Ответ 3
Вы должны иметь возможность правильно сортировать свои штрихи, сохраняя предыдущее местоположение всех касаний, а затем сравнивая эти предыдущие местоположения при обнаружении новых касаний.
В вашем методе -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 (или использовать другой тип массива).