Unpinch пользовательский распознаватель жестов с тремя пальцами в iOS

Я хочу сделать пользовательский распознаватель жестов с три пальцы. Что похоже на распознаватель жестов unpinch.

все, что мне нужно-это идея о том, как распознать его.

мой жест должен распознавать три пальца с тремя направлениями. Например:

enter image description here

enter image description here

enter image description here

Я надеюсь, что образы, смысл. Мне нужно сделать его гибким для любых трех противоположное направление. спасибо заранее. Любая помощь будет оценена.

Я знаю о методах подкласса, и я уже создал пользовательские жесты одним пальцем, как полукруг, полный круг. Мне нужно кодовое представление о том, как с этим справиться.

4 ответов


быстрая заметка для будущих читателей: как вы делаете unpinch/pinch тремя пальцами,добавьте расстояния ab,bc, ac.

однако, если ваш графический пакет просто случается иметь под рукой "площадь треугольника" - просто использовать, что. ("Он сохраняет целую строку кода!")

надеюсь, что это помогает.


все, что вам нужно сделать, это отслеживать:

расстояние между тремя пальцами!

просто добавьте "каждый" перестановка

(Ну, есть три .. ab, ac и cb. Просто добавьте их; вот и все!)

когда это значение, скажем, утроится от начального значения, это "outwards triple unpinch".

... удивительно это просто.

углы не имеют значения.


сноска если вы хотите быть умником: это относится к любому жесту щепотки/unpinch, 2, 3 пальца, что угодно:

отслеживать производную сумма-расстояние (я хочу сказать, скорость), а не расстояние. (Как ни странно, это часто легче сделать! потому что он безгосударственный! достаточно посмотреть на предыдущий кадр!!!!)

таким образом, другими словами, жест является триггером, когда скорость расширения/сжатия пальцев достигает определенного значения, а не кратного начального значения.


более интересная сноска!

есть тонкий проблема: всякий раз, когда вы делаете что-то подобное (любая платформа) вы должны быть осторожны, чтобы измерить "по стеклу".

Если вы просто делаете расстояние (т. е. мое первое решение выше), конечно, все отменяется, и вы можете просто сказать "если он удваивается" (в пикселях-точки-что угодно, черт возьми). Но если вы делаете скорость как часть расчета в любом жесте, то несколько удивительно,вы должны буквально найти скорость в метрах в секунду в реальный мир, что звучит странно на первый! Конечно, вы не можете сделать это точно (особенно с Android), потому что размеры стекла несколько отличаться, но вы должны приблизиться к нему. Вот длинный пост, обсуждающий эту проблему http://answers.unity3d.com/questions/292333/how-to-calculate-swipe-speed-on-ios.html на практике вам обычно приходится иметь дело с" шириной экрана в секунду", что довольно хорошо. (Но это может сильно отличаться на телефонах, больших планшетах, и эти дни "поверхностного" типа. на всем экране iMac 0,1 screenwidthspersecond может быть быстрым, но на iPhone это ничего, а не жест.)


заключительная сноска! Я просто не знаю, использует ли Apple "расстояние многократное" или "скорость стекла" в их распознавании жестов, или также, вероятно, какая-то тонкая смесь. Я никогда не читал статьи из их комментариев.


еще одна сноска! -- если по какой-то причине вы хотите найти "центр" треугольник!--4--> (Я имею в виду центр три пальца). Это хорошо распространенная проблема для игровых программистов, потому что, в конце концов, все 3D-сетки-это треугольники.

к счастью, тривиально найти центр трех точек, просто добавьте три вектора и разделите на три! (Как ни странно, это работает даже в высших измерениях!!)

вы можете увидеть бесконечные сообщения на этом вопрос...

http://answers.unity3d.com/questions/445442/calculate-uv-at-center-of-triangle.html

http://answers.unity3d.com/questions/424950/mid-point-of-a-triangle.html

возможно, если бы Вы были невероятно анальным, вы хотели бы "барицентр", который больше похож на центр масс, просто google, если вы этого хотите.


вам нужно создать UIGestureRecognizer собственный подкласс (назовем его DRThreeFingerPinchGestureRecognizer) и в его реализации:

– touchesBegan:withEvent:
– touchesMoved:withEvent:
– touchesEnded:withEvent:
– touchesCancelled:withEvent:

эти методы вызываются, когда касания принимаются системой и, возможно, до их отправки в само представление (в зависимости от того, как вы настраиваете распознаватель жестов). Каждый из этих методов даст вам набор штрихов, для которых вы можете проверить текущее местоположение в своем представлении и предыдущее местоположение. Поскольку жест щипка относительно очень прост, это информация достаточно для вас, чтобы проверить, если пользователь выполняет щепотку, и провалить тест (UIGestureRecognizerStateFailed). Если состояние не было нарушено – touchesEnded:withEvent:, вы можете узнать жест.

Я говорю, что жесты щипка просты, потому что вы можете легко отслеживать каждое прикосновение и видеть, как оно движется по сравнению с другими прикосновениями и собой. Если порог угла пройден и нарушен, вы проваливаете тест, в противном случае вы позволяете ему продолжаться. Если прикосновения не перемещаются под разными углами друг к другу, вы терпите неудачу тест. Вам придется играть с тем, что углы векторов являются приемлемыми, потому что 120 градусов не являются оптимальными для трех основных пальцев (большой + указательный + средний пальцы). Вы можете просто проверить, что векторы не сталкиваются.

обязательно прочитайте UIGestureRecognizer документация для углубленного взгляда на различные методы, а также примечания подклассов.


Я думаю, что углы трека ведут вас по неправильному пути. Я думаю, что это, вероятно, более гибкий и интуитивный жест, если вы не сдерживаете его, основываясь на углах между пальцами. Он будет менее подвержен ошибкам, если вы просто будете иметь дело с ним как с трехпалым щипком, независимо от того, как пальцы движутся относительно друг друга. Вот что бы я сделал:--3-->

if(presses != 3) {
     state = UIGestureRecognizerStateCancelled;
     return;
}

// After three fingers are detected, begin tracking the gesture.
state =  UIGestureRecognizerStateBegan; 
central_point_x = (point1.x + point2.x + point3.x) / 3;
central_point_y = (point1.y + point2.y + point3.y) / 3;

// Record the central point and the average finger distance from it.
central_point = make_point(central_point_x, central_point_y);
initial_pinch_amount = (distance_between(point1, central_point) + distance_between(point2, central_point) + distance_between(point3, central_point)) / 3;

затем на каждом обновлении для прикосновений переехали:

if(presses != 3) {
     state = UIGestureRecognizerStateEnded;
     return;
}

// Get the new central point
central_point_x = (point1.x + point2.x + point3.x) / 3;
central_point_y = (point1.y + point2.y + point3.y) / 3;
central_point = make_point(central_point_x, central_point_y);

// Find the new average distance
pinch_amount = (distance_between(point1, central_point) + distance_between(point2, central_point) + distance_between(point3, central_point)) / 3;

// Determine the multiplicative factor between them.
difference_factor = pinch_amount / initial_pinch_amount

после этого вы можете сделать все, что угодно с difference_factor. Если он больше 1, то щепотка отодвинулась от центра. Если меньше единицы, то она движется к центру. Это также даст пользователю возможность удерживать два пальца неподвижно и перемещать только третий, чтобы выполнить ваш жест. Это позволит решить некоторые проблемы доступности, с которыми могут столкнуться ваши пользователи.

кроме того, вы всегда можете отслеживать инкрементное изменение между событиями перемещения касания, но они не будут одинаково разнесены во времени, и я подозреваю у тебя будет больше проблем с этим.

Я также прошу прощения за псевдо-код. Если что-то не ясно, я могу посмотреть на реальный пример.


простой подкласс UIGestureRecognizer. Он вычисляет относительный треугольный центр из 3 точек, а затем вычисляет среднее расстояние от этого центра, угол не имеет значения. Затем вы проверяете среднее расстояние в обработчике жестов.

.h

#import <UIKit/UIKit.h>
#import <UIKit/UIGestureRecognizerSubclass.h>
@interface UnPinchGestureRecognizer : UIGestureRecognizer
 @property CGFloat averageDistanceFromCenter;
@end

#import "UnPinchGestureRecognizer.h"
@implementation UnPinchGestureRecognizer

-(CGPoint)centerOf:(CGPoint)pnt1 pnt2:(CGPoint)pnt2 pnt3:(CGPoint)pnt3
{
    CGPoint center;
    center.x = (pnt1.x + pnt2.x + pnt3.x) / 3;
    center.y = (pnt1.y + pnt2.y + pnt3.y) / 3;
    return center;
}
-(CGFloat)averageDistanceFromCenter:(CGPoint)center pnt1:(CGPoint)pnt1 pnt2:(CGPoint)pnt2 pnt3:(CGPoint)pnt3
{
    CGFloat distance;
    distance = (sqrt(fabs(pnt1.x-center.x)*fabs(pnt1.x-center.x)+fabs(pnt1.y-center.y)*fabs(pnt1.y-center.y))+
                sqrt(fabs(pnt2.x-center.x)*fabs(pnt2.x-center.x)+fabs(pnt2.y-center.y)*fabs(pnt2.y-center.y))+
                sqrt(fabs(pnt3.x-center.x)*fabs(pnt3.x-center.x)+fabs(pnt3.y-center.y)*fabs(pnt3.y-center.y)))/3;
    return distance;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    if ([touches count] == 3) {
        [super touchesBegan:touches withEvent:event];
        NSArray *touchObjects = [touches allObjects];
        CGPoint pnt1 = [[touchObjects objectAtIndex:0] locationInView:self.view];
        CGPoint pnt2 = [[touchObjects objectAtIndex:1] locationInView:self.view];
        CGPoint pnt3 = [[touchObjects objectAtIndex:2] locationInView:self.view];

        CGPoint center = [self centerOf:pnt1 pnt2:pnt2 pnt3:pnt3];
        self.averageDistanceFromCenter = [self averageDistanceFromCenter:center pnt1:pnt1 pnt2:pnt2 pnt3:pnt3];
        self.state = UIGestureRecognizerStateBegan;
    }
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {

    if ([touches count] == 3)
    {
        NSArray *touchObjects = [touches allObjects];
        CGPoint pnt1 = [[touchObjects objectAtIndex:0] locationInView:self.view];
        CGPoint pnt2 = [[touchObjects objectAtIndex:1] locationInView:self.view];
        CGPoint pnt3 = [[touchObjects objectAtIndex:2] locationInView:self.view];

        CGPoint center = [self centerOf:pnt1 pnt2:pnt2 pnt3:pnt3];
        self.averageDistanceFromCenter = [self averageDistanceFromCenter:center pnt1:pnt1 pnt2:pnt2 pnt3:pnt3];
        self.state = UIGestureRecognizerStateChanged;
        return;
    }

}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesEnded:touches withEvent:event];
    self.state = UIGestureRecognizerStateEnded;
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesEnded:touches withEvent:event];
    self.state = UIGestureRecognizerStateFailed;
}

@end

реализация жеста, у меня есть максимальное расстояние avg, установленное для начала, а затем минимум до конца, вы также можете проверить во время изменения:

-(IBAction)handleUnPinch:(UnPinchGestureRecognizer *)sender
{
    switch (sender.state) {
        case UIGestureRecognizerStateBegan:
            //If you want a maximum starting distance
            self.validPinch = (sender.averageDistanceFromCenter<75);
            break;
        case UIGestureRecognizerStateEnded:
            //Minimum distance from relative center
            if (self.validPinch && sender.averageDistanceFromCenter >=150) {
                NSLog(@"successful unpinch");
            }
            break;
        default:
            break;
    }
}