Использование UIPanGestureRecognizer в Xcode и скорости для определения направления смахивания слишком чувствительно и быстро переключается между направлениями

Уточнение:

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

Так что это должно произойти, когда состояние UIGestureRecognizerStateBegan загружает ссылку и перемещает камеру непрерывно, пока пользователь не коснется экрана, а состояние не станет UIGestureRecognizerStateEnded и вызовет другую ссылку html для запуска в WebView, которая остановит камеру. от переезда. Пока мы говорим, мой первоначальный опубликованный код делает это, но пролистывание было слишком чувствительным. Эта проблема исправлена ​​вашим кодом, но теперь вторая ссылка загружается сразу после первой, не позволяя камере двигаться. Имеет ли это смысл?? Первая ссылка должна работать до тех пор, пока палец не будет поднят.


Оригинальный вопрос:

Я пытался определить направление прокрутки, используя скорость в UIPanGestureRecognizer, которым я управлял, и он обнаруживает пролистывания вправо, влево, вверх и вниз, запускает соответствующие действия в зависимости от направления пролистывания и снова правильные действия, когда UIGestureRecognizerStateEnded для каждого пролистывания , НО, моя проблема в приведенном ниже коде заключается в том, что направление очень чувствительно, например, во время пролистывания вправо оно распознает большую часть пролистывания вправо, но также некоторые пролистывания вверх или вниз между ними. Поскольку смахивание не всегда идеально проходит по прямой линии, я хотел бы найти запуск действия для смахивания вправо только в том случае, если свайп БОЛЬШИНСТВЕННО вправо, и игнорировать крошечные отклонения пикселей.

Кроме того, в идеале для моего проекта нужно инициировать действие в заданном направлении смахивания только один раз, как в UISwipeGestureRecognizer, но при его использовании у меня возникла проблема с UIGestureRecognizerStateEnded, поскольку он не позволяет выполнять действие смахивания, пока я не уберу палец с экран, он сразу же завершает действие смахивания, хотя мой палец все еще проводит свайпом.

Любая помощь приветствуется. Вот мой код:

в ViewDidLoad у меня есть:

UIPanGestureRecognizer *gestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];
[_myWebView addGestureRecognizer:gestureRecognizer];
[gestureRecognizer setMinimumNumberOfTouches:1];
[gestureRecognizer setMaximumNumberOfTouches:1];

и в моем классе у меня есть:

- (void)handleGesture:(UIPanGestureRecognizer *)gestureRecognizer
{
CGPoint velocity = [gestureRecognizer velocityInView:_myWebView];

if(velocity.x > 0)//right
{
   //my action here

  if ( [gestureRecognizer state] == UIGestureRecognizerStateEnded )
  { //my action when swipe finished here }
}
else if(velocity.x < 0)//left
{
   //my action here

  if ( [gestureRecognizer state] == UIGestureRecognizerStateEnded )
  { //my action when swipe finished here }
}
else if(velocity.y > 0)//down
{
   //my action here

  if ( [gestureRecognizer state] == UIGestureRecognizerStateEnded )
  { //my action when swipe finished here }
}
else if(velocity.y < 0)//up
{
   //my action here

  if ( [gestureRecognizer state] == UIGestureRecognizerStateEnded )
  { //my action when swipe finished here }
}

Спасибо, любые уточнения спрашивайте.


person Dashony    schedule 14.12.2012    source источник


Ответы (2)


У вас могло бы быть некоторое «горизонтальное» определение направления, если бы компонент x был некоторым разумным кратным компоненту y. Итак, возможно, если бы x было пять раз y, это можно было бы считать горизонтальным смахиванием. И наоборот по вертикали. Является ли пять правильным кратным, зависит от вас (используя tan-1, вы можете видеть, что это соответствует примерно 11,3 от абсолютного горизонтального/вертикального), но концептуально это один из способов легко решить эту проблему.

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

CGFloat const gestureMinimumTranslation = 20.0;

typedef enum : NSInteger {
    kCameraMoveDirectionNone,
    kCameraMoveDirectionUp,
    kCameraMoveDirectionDown,
    kCameraMoveDirectionRight,
    kCameraMoveDirectionLeft
} CameraMoveDirection;

@interface ViewController ()
{
    CameraMoveDirection direction;
}
@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    UIPanGestureRecognizer *recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipe:)];
    [self.viewWithGestureRecognizer addGestureRecognizer:recognizer];
}

// This is my gesture recognizer handler, which detects movement in a particular
// direction, conceptually tells a camera to start moving in that direction
// and when the user lifts their finger off the screen, tells the camera to stop.

- (void)handleSwipe:(UIPanGestureRecognizer *)gesture
{
    CGPoint translation = [gesture translationInView:self.view];

    if (gesture.state == UIGestureRecognizerStateBegan)
    {
        direction = kCameraMoveDirectionNone;
    }
    else if (gesture.state == UIGestureRecognizerStateChanged && direction == kCameraMoveDirectionNone)
    {
        direction = [self determineCameraDirectionIfNeeded:translation];

        // ok, now initiate movement in the direction indicated by the user's gesture

        switch (direction) {
            case kCameraMoveDirectionDown:
                NSLog(@"Start moving down");
                break;

            case kCameraMoveDirectionUp:
                NSLog(@"Start moving up");
                break;

            case kCameraMoveDirectionRight:
                NSLog(@"Start moving right");
                break;

            case kCameraMoveDirectionLeft:
                NSLog(@"Start moving left");
                break;

            default:
                break;
        }
    }
    else if (gesture.state == UIGestureRecognizerStateEnded)
    {
        // now tell the camera to stop
        NSLog(@"Stop");
    }
}

// This method will determine whether the direction of the user's swipe

- (CameraMoveDirection)determineCameraDirectionIfNeeded:(CGPoint)translation
{
    if (direction != kCameraMoveDirectionNone)
        return direction;

    // determine if horizontal swipe only if you meet some minimum velocity

    if (fabs(translation.x) > gestureMinimumTranslation)
    {
        BOOL gestureHorizontal = NO;

        if (translation.y == 0.0)
            gestureHorizontal = YES;
        else
            gestureHorizontal = (fabs(translation.x / translation.y) > 5.0);

        if (gestureHorizontal)
        {
            if (translation.x > 0.0)
                return kCameraMoveDirectionRight;
            else
                return kCameraMoveDirectionLeft;
        }
    }
    // determine if vertical swipe only if you meet some minimum velocity

    else if (fabs(translation.y) > gestureMinimumTranslation)
    {
        BOOL gestureVertical = NO;

        if (translation.x == 0.0)
            gestureVertical = YES;
        else
            gestureVertical = (fabs(translation.y / translation.x) > 5.0);

        if (gestureVertical)
        {
            if (translation.y > 0.0)
                return kCameraMoveDirectionDown;
            else
                return kCameraMoveDirectionUp;
        }
    }

    return direction;
}

@end

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

person Rob    schedule 14.12.2012
comment
Хорошо, это решение правильно определяет право, лево, вверх и вниз, но моя другая проблема все еще существует. Действие начинается, как только оно идентифицирует действительное смахивание, и мгновенно завершается, даже если мой палец все еще проводит свайпом, запуская другое мое действие. Что мне нужно, так это чтобы мое первое действие начиналось, как только я начинал смахивать, и заканчивало работу только тогда, когда мой палец выключен, когда он запускает мое второе действие. - person Dashony; 17.12.2012
comment
Спасибо за решение, Роб, за мою проблему со смахиванием, теперь направление смахивания определяется правильно и вызывает действие только один раз, а не 15 раз. Моя большая проблема с приведенным выше кодом заключается в том, что теперь он не идентифицирует, что мой палец находится вне экрана, поэтому UIGestureRecognizerStateEnded вызывается только тогда, когда смахивание заканчивается, когда палец отрывается от экрана, поэтому начинается мое второе действие. Надеюсь, я достаточно ясен, если нет, я постараюсь дать больше информации. - person Dashony; 17.12.2012
comment
спасибо за редактирование для меня. Я собирался, но заметил, что ты это сделал. Тогда спасибо - person Dashony; 17.12.2012
comment
Пользователь управляет только направлением движения (вверх, вниз, вправо, влево). Действие должно продолжаться до тех пор, пока палец не будет поднят, иначе будет слишком много движений, чтобы переместить камеру на 280 градусов. - person Dashony; 17.12.2012
comment
Вывод: Свайп вправо - html-ссылка загружается и работает (камера начинает вращаться) - поднимите палец - загружается другая html-ссылка, которая останавливает вращение камеры - person Dashony; 17.12.2012
comment
спасибо, сейчас попробую, скоро напишу. Извините за все хлопоты. Я признаю, что просто недостаточно ясно выразился. - person Dashony; 17.12.2012
comment
Роб, ты думал, что мне сегодня нужно несколько уроков. Не только исправляя и в значительной степени перепечатывая свой код, я также научился немного лучше объяснять себя, когда прошу о помощи. Я ДЕЙСТВИТЕЛЬНО ЦЕНЮ ВАШУ ПОМОЩЬ, РОБ, И ДА, КОД - ТОЧНО ТО, ЧТО МНЕ НУЖНО И РАБОТАЕТ ОТЛИЧНО !!! СПАСИБО, СЭР ! - person Dashony; 17.12.2012

Во-первых, вы можете использовать перевод вместо скорости жеста — это даст вам расстояние, пройденное от начала до конца свайпа, а не направление движения в самом конце свайпа, как со скоростью.

Во-вторых, вам, вероятно, следует проверить, является ли состояние жеста «Завершенным», прежде чем проверять направление. Теперь вы повторяете ту же проверку в каждом «если».

Чтобы получить направление, вы можете либо получить угол перевода, используя тригонометрическую функцию atan2 с x и y перевода, либо, если это нормально, всегда интерпретировать жест как пролистывание в одном из 4 направлений, просто найдите, больше ли x или y абсолютное значение, а затем, если оно положительное или отрицательное.

person konrad    schedule 14.12.2012
comment
OP, вероятно, не хочет проверять конец жеста, иначе было бы лучше использовать жесты смахивания; это любопытная проблема, которую пытается решить ОП. Лично я думаю, что ему следует использовать стандартный UISwipeGestureRecognizer, поскольку желаемый жест OP очень нестандартен (обычно у пользователя всегда должна быть возможность эффективно отменить жест после его запуска, а решение OP этого не предоставляет). Но каждому свое. - person Rob; 14.12.2012
comment
Вы правы, но из того, что я понял, он хотел бы распознавать направление как во время, так и в конце жеста. Это делает мой второй пункт недействительным, а что касается использования перевода, то я не уверен, хотел бы он измерять направление движения с самого начала или в любой данный момент. Когда дело доходит до измерения направления, ваш ответ действительно в порядке. Я мог бы только добавить, что для уменьшения «случайности» направления он мог хранить массив последних нескольких позиций жестов как историю и сравнивать последнюю с одной n-й предыдущей. - person konrad; 14.12.2012
comment
Согласованный. Я обновил свой ответ, чтобы распознаватель жестов отменял себя, как только он успешно идентифицирует жест, чтобы убедиться, что у вас нет каких-либо посторонних распознаваний, например, когда пользователь отрывает палец от экрана. - person Rob; 14.12.2012