Спасибо за ответы, они помогли мне решить ситуацию с «оверлейными» представлениями.
+----------------------------+
|A +--------+ |
| |B +------------------+ |
| | |C X | |
| | +------------------+ |
| | | |
| +--------+ |
| |
+----------------------------+
Предположим, X
- касание пользователя.pointInside:withEvent:
on B
возвращает NO
, поэтому hitTest:withEvent:
возвращает A
.Я написал категорию на UIView
, чтобы решить проблему, когда вам нужно получить сенсорный вид сверху видимый вид.
- (UIView *)overlapHitTest:(CGPoint)point withEvent:(UIEvent *)event {
// 1
if (!self.userInteractionEnabled || [self isHidden] || self.alpha == 0)
return nil;
// 2
UIView *hitView = self;
if (![self pointInside:point withEvent:event]) {
if (self.clipsToBounds) return nil;
else hitView = nil;
}
// 3
for (UIView *subview in [self.subviewsreverseObjectEnumerator]) {
CGPoint insideSubview = [self convertPoint:point toView:subview];
UIView *sview = [subview overlapHitTest:insideSubview withEvent:event];
if (sview) return sview;
}
// 4
return hitView;
}
- Мы не должны отправлять сенсорные события для скрытого или прозрачногопросмотры или просмотры с
userInteractionEnabled
, установленным на NO
; - Если касание внутри
self
, self
будет рассматриваться как потенциальный результат. - Рекурсивно проверять все подпредставления на предмет попадания,Если есть, верните его.
- В противном случае верните self или nil в зависимости от результата из шага 2.
Обратите внимание, [self.subviewsreverseObjectEnumerator]
необходимо, чтобы следовать иерархии просмотра сверху вниз.И проверьте clipsToBounds
, чтобы не проверять маскированные подпредставления.
Использование:
- Импортировать категорию в подклассе.
- Заменить
hitTest:withEvent:
этим
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
return [self overlapHitTest:point withEvent:event];
}
Официальное руководство Apple также содержит несколько хороших иллюстраций.
Надеюсь, это кому-нибудь поможет.