Отключите прикосновения к фону UIView, чтобы кнопки на нижних экранах можно было нажимать
В основном, это моя иерархия представлений (и я прошу прощения, если это трудно читать... Я новичок здесь, поэтому я с радостью принимаю предложения)
--AppControls.xib
------- (UIView) ControlsView
----------------- (UIView) TopBar
----------------- -------------- btn1, btn2, btn3
----------------- UIView) BottomBar
----------------- -------------- slider1 btn1, btn2
--PageContent.xib
----------------- (UIView) ContentView
----------------- -------------- btn1, btn2, btn3
----------------- -------------- (UIImageView) FullPageImage
Моя ситуация заключается в том, что я хочу скрыть и показать элементы управления при нажатии в любом месте на PageContent, который не является кнопкой, и чтобы элементы управления отображались, как в iPhone Video Player. Тем не менее, когда элементы управления отображаются, я все еще хочу иметь возможность нажимать кнопки на PageContent.
У меня все это работает, кроме последней части. Когда элементы управления показывают, фон элементов управления получает события касания вместо представления ниже. А отключение взаимодействия с пользователем в ControlsView отключает его для всех его дочерних элементов.
Я попытался переопределить HitTest на моем подклассе ControlsView следующим образом, который я нашел в аналогичном посте:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
UIView *hitView = nil;
NSArray *subviews = [self subviews];
int subviewCount = [subviews count];
for (int subviewIndex = 0; !hitView && subviewIndex < subviewCount; subviewIndex++){
hitView = [[subviews objectAtIndex:subviewIndex] hitTest:point withEvent:event];
}
return hitView;
}
Тем не менее, в этот момент мой ползунок не работает, как и большинство других кнопок, и на самом деле, все начинает становиться странным.
Итак, мой вопрос вкратце: как я могу позволить всем подпредставлениям вида иметь сенсорные события, в то время как фон суперпредставления не щелкает мышью, и кнопки на представлениях ниже могут получать сенсорные события.
Спасибо!
4 ответа
Ты рядом. Не переопределять -hitTest:withEvent:
, К тому времени, когда вызывается, диспетчер событий уже решил, что ваше поддерево иерархии владеет событием и не будет искать в другом месте. Вместо этого переопределите -pointInside:withEvent:
, который вызывается ранее в конвейере обработки событий. Это то, как система спрашивает: "Эй, взгляд, НИКТО в вашей иерархии реагирует на событие в этот момент?". Если вы говорите "НЕТ", обработка события продолжается ниже видимого стека.
Согласно документации, реализация по умолчанию просто проверяет, находится ли точка в границах представления вообще.
Ваша стратегия состоит в том, чтобы сказать "да", когда любое из ваших подпредставлений находится по этой координате, но сказать "нет", когда прикосновение коснется фона.
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
for (UIView * view in [self subviews]) {
if (view.userInteractionEnabled && [view pointInside:[self convertPoint:point toView:view] withEvent:event]) {
return YES;
}
}
return NO;
}
Благодаря @Ben Zutto, решение Swift 3:
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
for view in self.subviews {
if view.isUserInteractionEnabled, view.point(inside: self.convert(point, to: view), with: event) {
return true
}
}
return false
}
Небольшой вариант ответа Бена, имеющий дело с детьми, которые выходят за пределы их родителей. Если clipChildren имеет значение YES, это не вернет YES для точек, которые находятся вне основного элемента управления, но внутри какого-либо дочернего элемента. если clipChildren НЕТ, это то же самое, что и у Бена.
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
BOOL clipChildren = YES;
if (!clipChildren || [super pointInside:point withEvent:event]) {
for (UIView * view in [self subviews]) {
if (view.userInteractionEnabled && [view pointInside:[self convertPoint:point toView:view] withEvent:event]) {
return YES;
}
}
}
return NO;
}
Другой подход может заключаться в том, чтобы иметь невидимую полноэкранную кнопку позади всего остального и предпринимать соответствующие действия при ее нажатии.