Обнаружение горизонтальных пролистываний в UIScrollView с вертикальной прокруткой

У меня есть UIScrollView высотой около 600 пикселей и шириной 320 пикселей. Поэтому я разрешаю пользователю прокручивать по вертикали.

Я также пытаюсь захватить горизонтальные движения в представлении. Проблема, похоже, заключается в том, что когда пользователь проводит пальцем по горизонтали с каким-то случайным вертикальным движением, UIScrollView прокручивается, и мой метод делегата touchesEnded никогда не вызывается.

Вот мой код:

- (void)touchesEnded: (NSSet *)touches withEvent: (UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    CGPoint currentPosition = [touch locationInView:self];

    if (currentPosition.x + 35 < gestureStartPoint.x)
    {  
        NSLog(@"Right");
    }    
    else if (currentPosition.x - 35 > gestureStartPoint.x)
    {
        NSLog(@"Left");
    }    
    else if (!self.dragging)
    {
        [self.nextResponder touchesEnded: touches withEvent:event]; 
    }

    [super touchesEnded: touches withEvent: event];
}

Кто-нибудь знает, как я могу заставить это работать, даже если задействовано вертикальное сопротивление?


person tuzzolotron    schedule 24.09.2009    source источник


Ответы (3)


UIScrollView пытается выяснить, какие касания должны пройти к его содержимому, а какие являются прокруткой, основываясь на движении сразу после начала касания. По сути, если касание сразу выглядит как прокрутка, он обрабатывает этот жест, и содержимое никогда его не видит; в противном случае жест передается (с очень короткой задержкой для первого касания).

По моему опыту, мне удавалось фиксировать горизонтальные свайпы в содержимом UIScrollView, который обрабатывал только вертикальную прокрутку — в основном это работало у меня по умолчанию. Я сделал это, установив contentSize таким же, как ширина frame представления прокрутки, что является достаточной информацией, чтобы сообщить UIScrollView, что он не будет обрабатывать горизонтальную прокрутку.

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

Если это не сработает, вот очень подходящий абзац из документации Apple UIScrollView:

Поскольку представление прокрутки не имеет полос прокрутки, оно должно знать, сигнализирует ли касание о намерении прокрутки или о намерении отслеживать подпредставление в содержимом. Чтобы сделать это определение, он временно перехватывает событие касания, запуская таймер и, прежде чем таймер сработает, наблюдая, совершает ли касающийся палец какое-либо движение. Если время срабатывает без существенного изменения положения, представление прокрутки отправляет события отслеживания в подвид касания представления содержимого. Если затем пользователь перетаскивает палец достаточно далеко до истечения таймера, представление прокрутки отменяет любое отслеживание в подпредставлении и выполняет прокрутку самостоятельно. Подклассы могут переопределять touchesShouldBegin:withEvent:inContentView:, pagingEnabled и touchesShouldCancelInContentView: методы (которые вызываются представлением прокрутки), чтобы повлиять на то, как вид прокрутки обрабатывает жесты прокрутки.

Таким образом, вы можете попробовать то, что они предлагают, создав подкласс UIScrollView и переопределив предложенные методы.

person Tyler    schedule 24.09.2009
comment
Тайлер, спасибо за ответ. Я могу обнаруживать горизонтальные пролистывания, но только если они имеют очень-очень небольшое изменение по оси Y. Если я переместил более +-5 пикселей примерно по оси Y, кажется, что ScrollView берет верх и начинает прокручиваться по вертикали. Это не так реалистично, так как мне требуется несколько попыток (на устройстве), чтобы провести пальцем с этим небольшим изменением по оси Y. Вы сталкивались с подобным поведением? - person tuzzolotron; 04.10.2009

Если метод @Tyler не работает, попробуйте поместить представление прямо поверх UIScrollView и обработать любые горизонтальные пролистывания в touchesBegan этого представления и передать вертикальные пролистывания следующему респонденту. Вы можете быть немного нечетким и обрабатывать все, что имеет большее горизонтальное движение, чем вертикальное, как горизонтальное смахивание, и передавать более чистые вертикальные свайпы в UISCrollView (через nextResponder).

person mahboudz    schedule 26.09.2009
comment
Новый вид - это тот, который не получает никаких касаний? Это дочерний элемент прокрутки или родной брат над ним? Настроен ли он на взаимодействие с пользователем? - person mahboudz; 05.10.2009

Решение Swift 4

Зарегистрируйте два распознавателя жестов в viewDidLoad() в вашем контроллере представления.

let leftGesture = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipe(_:)))
leftGesture.direction = .left
leftGesture.delegate = self
view.addGestureRecognizer(leftGesture)

let rightGesture = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipe(_:)))
rightGesture.direction = .right
rightGesture.delegate = self
view.addGestureRecognizer(rightGesture)

Реализовать действие смахивания

@objc func handleSwipe(_ sender: UISwipeGestureRecognizer) {
    // do swipe left/right based on sender.direction == .left / .right
}

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

class MyViewController: UIViewController, UIGestureRecognizerDelegate

...

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
                       shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    return true
}

Последний шаг устраняет проблему, заключающуюся в том, что при перемещении более чем на +/- 5 пикселей по оси Y представление прокрутки берет верх и начинает прокручиваться по вертикали.

person Vladimir Grigorov    schedule 15.05.2019