Проходя через прикосновения к UIViews под - PullRequest
62 голосов
/ 27 января 2012

У меня есть UIView с 4 кнопками на нем и еще одна UIView поверх вида кнопок. Самый верхний вид содержит UIImageView с UITapGestureRecognizer на нем.

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

У меня есть это в моем initWithFrame: виде сверху:

// Add a gesture recognizer to the image view
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(imageTapped:)];
tapGestureRecognizer.cancelsTouchesInView = NO;
[imageView addGestureRecognizer:tapGestureRecognizer];
[tapGestureRecognizer release];

а я это мой imageTapped: метод:

- (void) imageTapped:(UITapGestureRecognizer *) gestureRecognizer {
    // Toggle between expanding and contracting the image
    if (expanded) {
        [self contractAnimated:YES];
        expanded = NO;
        gestureRecognizer.cancelsTouchesInView = NO;
        self.userInteractionEnabled = NO;
        self.exclusiveTouch = NO;
    }
    else {
        [self expandAnimated:YES];
        expanded = YES;
        gestureRecognizer.cancelsTouchesInView = NO;
        self.userInteractionEnabled = YES;
        self.exclusiveTouch = YES;
    }
}

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

Если я установлю self.userInteractionEnabled = YES в обоих случаях, то при касании изображение расширяется и сжимается, но кнопки никогда не получают прикосновения и действуют как отключенные.

Есть ли где-нибудь, чтобы изображение растягивалось и сжималось при прикосновении, а кнопки внизу могли получать прикосновения только в том случае, если изображение находится в сжатом состоянии? Я делаю что-то глупое и упускаю что-то очевидное?

Я схожу с ума, пытаясь заставить это работать, поэтому любая помощь будет оценена,

Dave

UPDATE:

Для дальнейшего тестирования я переопределил методы touchesBegan: и touchesCancelled: и вызвал их супер реализации в моем представлении, содержащем UIImageView. С кодом выше, touchesCancelled: никогда не вызывается, а touchesBegan: всегда вызывается.

Так что может показаться, что вид получает штрихи, они просто не передаются представлению внизу.

UPDATE

Это из-за того, как работает цепочка респондента? Моя иерархия представлений выглядит так:

VC - View1
     -View2
      -imageView1 (has tapGestureRecogniser)
      -imageView2
     -View3
      -button1
      -button2

Я думаю, что ОС сначала выполняет hitTest, поскольку говорит, что View2 находится впереди, поэтому должен получить все касания, и они никогда не будут переданы View3, если для userInteractions не установлено значение NO для View2, и в этом случае imageView1 также не может получить прикасается. Вот как это работает, и есть ли способ для View2 пройти через его прикосновения к View3?

Ответы [ 6 ]

90 голосов
/ 27 января 2012

UIGestureRecognizer - красная сельдь, я думаю.В конце концов, чтобы решить эту проблему, я переопределил метод pointInside:withEvent: моего UIView:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    BOOL pointInside = NO;

    if (CGRectContainsPoint(imageView.frame, point) || expanded) pointInside = YES;

    return pointInside;
}

. Это заставляет представление перехватывать все касания, если вы касаетесь либо imageView, либо если установлен его расширенный флаг.Если он не развернут, то только прикасайтесь к касаниям, если они находятся в imageView.

Возвращая NO, View верхнего уровня VC запрашивает остальную часть своей иерархии представления в поисках попадания.

59 голосов
/ 22 июня 2015

Выберите ваши View в Storyboard или XIB и ...


enter image description here


Или на Свифте

view.isUserInteractionEnabled = false
6 голосов
/ 27 января 2012

Просмотрите протокол UIGestureRecognizerDelegate .В частности, gestureRecognizer:shouldReceiveTouch:

Вы захотите сделать каждый UIGestureRecognizer свойством UIViewController,

// .h
@property (nonatomic, strong) UITapGestureRecognizer *lowerTap;

// .m
@synthesize lowerTap;

// When you are adding the gesture recognizer to the image view
self.lowerTap = tapGestureRecognizer

Убедитесь, что ваш UIViewController делегат,

[self.lowerTap setDelegate: self];

Тогда у вас будет что-то вроде этого:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    if (expanded && gestureRecognizer == self.lowerTap) {    
        return NO;
    }
    else {
        return YES;
    }
}

Конечно, это не точный код.Но такова общая схема, которой вы хотели бы следовать.

2 голосов
/ 07 февраля 2018

@ Решение Magic Bullet Дейва, но в Swift

Свифт 3

override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
    var pointInside = false
    if commentTextField.frame.contains(point) {
        pointInside = true
    } else {
        commentTextField.resignFirstResponder()
    }
    return pointInside
}

Я использую его в CameraOverlayView для ImagePickerViewController.cameraOverlay, чтобы дать пользователю возможность комментировать при съемке новой фотографии

2 голосов
/ 16 марта 2016

У меня есть другое решение.У меня есть два вида, давайте назовем их CustomSubView, которые перекрывались, и они оба должны получить штрихи.Итак, у меня есть контроллер представления и пользовательский класс UIView, давайте назовем его ViewControllerView, который я установил в построителе интерфейса, затем я добавил два представления, которые должны получать прикосновения к этому представлению.

Итак, я перехватилприкосновения в ViewControllerView путем перезаписи hitTest:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    return self;
}

Затем я переписал в ViewControllerView:

- (void)touchesBegan:(NSSet *)touches
           withEvent:(UIEvent *)event
{
    [super touchesBegan:touches withEvent:event];
    for (UIView *subview in [self.subviews reverseObjectEnumerator])
    {
        if ([subview isKindOfClass:[CustomSubView class]])
        {
            [subview touchesBegan:touches withEvent:event];
        }
    }
}

Точно так же с touchesMoved touchesEnded и touchesCancelled.

0 голосов
/ 13 марта 2018
// this is due to userInteractionEnabled deficiency: the flag stops traversal of subviews
@objc(YourObjcPrefixHereForXibAndStoryboardUseViewTransparentToTouch)
open class ViewTransparentToTouch: UIView
{
public var daisyView: UIView?
override open func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
    let hitView = super.hitTest(point, with: event)
    if hitView === self {
        return daisyView
    }
    return hitView // childView
}
}
...