Подтвердить что ты не робот

Разрешить UIScrollView и его подзаголовкам отвечать на прикосновение

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

В качестве альтернативы, если жесты нажатия были переадресованы в подпункты, все будет хорошо.

Многие люди борются в этой общей области. Вот несколько из многих связанных вопросов:

Как кражи UIScrollView касаются его подзонов
Как украсть штрихи от UIScrollView? Как отменить прокрутку в UIScrollView

Кстати, если я переопределяю hitTest: withEvent: в представлении прокрутки я вижу касания до тех пор, пока userInteractionEnabled равен YES. Но это действительно не решает мою проблему, потому что:

1) В этот момент я не знаю, если это кран или нет.
2) Иногда мне нужно установить userInteractionEnabled в НЕТ.

РЕДАКТИРОВАТЬ: Чтобы прояснить, да, я хочу обрабатывать краны по-разному от сковородок. Отводы должны обрабатываться подзонами. Кастрюли могут обрабатываться в виде прокрутки обычным способом.

4b9b3361

Ответ 1

Во-первых, отказ от ответственности. Если вы установите userInteractionEnabled на NO на UIScrollView, сенсорные события не будут переданы в подзоны. Насколько мне известно, нет никакого способа обойти это с одним исключением: перехватить сенсорные события над надстройкой UIScrollView и, в частности, передать эти события в подпункты UIScrollView. Если честно, я не знаю, почему вы хотели бы это сделать. Если вы хотите отключить определенные функции UIScrollView (например,... прокрутку), вы можете сделать это достаточно легко, не отключая UserInteraction.

Если я понимаю ваш вопрос, вам нужны события перехода, которые будут обрабатываться с помощью UIScrollView и, переданных в subviews? В любом случае (независимо от жестов), я думаю, что вы ищете метод протокола gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer: в протоколе UIGestureRecognizerDelegate, В ваших подзонах, независимо от того, какие у вас распознаватели жестов, установите делегат (возможно, любой класс устанавливает UIGestureReconginzer в первую очередь) на распознаватель жестов. Переопределите вышеуказанный метод и верните YES. Теперь этот жест будет распознан вместе с любыми другими распознавателями, которые могли бы "украсть" жест (в вашем случае, краном). Используя этот метод, вы можете даже точно настроить свой код, чтобы отправлять только отдельные виды жестов в подзаголовки или отправлять жест только в определенных ситуациях. Это дает вам большой контроль. Просто не забудьте прочитать о методе, особенно в этой части:

Этот метод вызывается при распознавании жестов посредством либо gestureRecognizer, либо другойGestureRecognizer блокирует другой распознаватель жестов признает его жест. Обратите внимание, что возврат ДА гарантирует возможность одновременного распознавания; возврат НЕТ, с другой стороны, не гарантируется одновременное распознавание, потому что другой распознаватель жестов делегат может вернуть ДА.

Конечно, есть оговорка: это касается только распознавателей жестов. Таким образом, у вас могут возникнуть проблемы, если вы пытаетесь использовать touchesBegan:, touchesEnded и т.д. Для обработки штрихов. Разумеется, вы можете использовать hitTest: для отправки сырых событий касания к подзонам, но почему? Зачем обрабатывать события с помощью этих методов в UIView, когда вы можете прикрепить UIGestureRecognizer к представлению и получить все эти функции бесплатно? Если вам нужны штрихи, обработанные таким образом, что ни один стандартный UIGestureRecognizer не может предоставить, подкласс UIGestureRecognizer и обрабатывать штрихи там. Таким образом, вы получаете все функциональные возможности UIGestureRecognizer, а также свою собственную сенсорную обработку. Я действительно думаю, что Apple предназначалась для UIGestureRecognizer для замены большинства (если не всех) настраиваемого кода обработки, который разработчики используют на UIView. Это позволяет повторно использовать код, и с ним легче справляться, если смягчить, какой код обрабатывает то, что касается события.

Ответ 2

Я не знаю, может ли это помочь вам, но у меня была аналогичная проблема, когда я хотел, чтобы scrollview обрабатывал двойное нажатие, но перетащил одно нажатие на subviews. Вот код, используемый в CustomScrollView

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {

    UITouch* touch = [touches anyObject];
    // Coordinates
    CGPoint point = [touch locationInView:[self.subviews objectAtIndex:0]];

    // One tap, forward
    if(touch.tapCount == 1){
        // for each subview
        for(UIView* overlayView in self.subviews){
            // Forward to my subclasss only
            if([overlayView isKindOfClass:[OverlayView class]]){
                // translate coordinate
                CGPoint newPoint = [touch locationInView:overlayView];
                //NSLog(@"%@",NSStringFromCGPoint(newPoint));

                BOOL isInside = [overlayView pointInside:newPoint withEvent:event];
                //if subview is hit
                if(isInside){
                    Forwarding
                    [overlayView touchesEnded:touches withEvent:event];
                    break;
                }
            }
        }

    }
    // double tap : handle zoom
    else if(touch.tapCount == 2){

        if(self.zoomScale == self.maximumZoomScale){
            [self setZoomScale:[self minimumZoomScale] animated:YES];
        } else {
            CGRect zoomRect = [self zoomRectForScrollView:self withScale:self.maximumZoomScale withCenter:point];            

            [self zoomToRect:zoomRect animated:YES];
        }

        [self setNeedsDisplay];

    }
}

Конечно, эффективный код должен быть изменен, но на этом этапе у вас должна быть вся информация, необходимая для принятия решения о необходимости переадресации события. Возможно, вам понадобится реализовать это в другом методе как касаниеMoved: withEvent:.

Надеюсь, это поможет.

Ответ 3

У меня была такая же проблема, но с прокруткой, которая находилась внутри UIPageViewController, поэтому ее нужно было обрабатывать несколько иначе.

Изменив свойство cancelsTouchesInView на false для каждого распознавателя на UIScrollView, я смог получить штрихи к кнопкам внутри UIPageViewController.

Я сделал это, добавив этот код в viewDidLoad:

guard let recognizers = self.pageViewController.view.subviews[0].gestureRecognizers else {
     print("No gesture recognizers on scrollview.")
     return
}

for recognizer in recognizers {
    recognizer.cancelsTouchesInView = false
}

Ответ 4

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

В этот момент вы можете установить логическое значение, чтобы указать, если movnent accoured и установить это Boolean как условие в других ваших методах.

Я нахожусь в дороге, но если это вам понадобится, я смогу объяснить лучше позже.

Ответ 5

Хакерный способ достижения вашей цели - не 100% точный - заключается в подклассе UIWindow и переопределении события - (void) sendEvent: (UIEvent *);

Быстрый пример:

в заголовке SecondResponderWindow.h

//SecondResponderWindow.h

@protocol SecondResponderWindowDelegate
- (void)userTouchBegan:(id)tapPoint onView:(UIView*)aView;
- (void)userTouchMoved:(id)tapPoint onView:(UIView*)aView;
- (void)userTouchEnded:(id)tapPoint onView:(UIView*)aView;
@end

@interface SecondResponderWindow : UIWindow
@property (nonatomic, retain) UIView *viewToObserve;
@property (nonatomic, assign) id <SecondResponderWindowDelegate> controllerThatObserves;
@end

в SecondResponderWindow.m

//SecondResponderWindow.m

- (void)forwardTouchBegan:(id)touch onView:(UIView*)aView {
    [controllerThatObserves userTouchBegan:touch onView:aView];
}
- (void)forwardTouchMoved:(id)touch onView:(UIView*)aView {
    [controllerThatObserves userTouchMoved:touch onView:aView];
}
- (void)forwardTouchEnded:(id)touch onView:(UIView*)aView {
    [controllerThatObserves userTouchEnded:touch onView:aView];
}

- (void)sendEvent:(UIEvent *)event {
    [super sendEvent:event];

    if (viewToObserve == nil || controllerThatObserves == nil) return;

    NSSet *touches = [event allTouches];
    UITouch *touch = [touches anyObject];
    if ([touch.view isDescendantOfView:viewToObserve] == NO) return;

    CGPoint tapPoint = [touch locationInView:viewToObserve];
    NSValue *pointValue = [NSValue valueWithCGPoint:tapPoint];

    if (touch.phase == UITouchPhaseBegan)
        [self forwardTouchBegan:pointValue onView:touch.view];
    else if (touch.phase == UITouchPhaseMoved)
        [self forwardTouchMoved:pointValue onView:touch.view];
    else if (touch.phase == UITouchPhaseEnded)
        [self forwardTouchEnded:pointValue onView:touch.view];
    else if (touch.phase == UITouchPhaseCancelled)
        [self forwardTouchEnded:pointValue onView:touch.view];
}

Это не 100% соответствует тому, что вы ожидали, потому что ваш второй ответчик не обрабатывает событие касания изначально через -touchDidBegin: или так, и ему нужно реализовать SecondResponderWindowDelegate. Однако этот хак позволяет обрабатывать события касания на дополнительных респондентах.

Этот метод вдохновлен и расширен от MITHIN KUMAR TapDetectingWindow