Как отключить сенсорный ввод ко всем представлениям, кроме самого верхнего вида?
У меня есть представление с несколькими subviews. Когда пользователь отбирает subview, subview расширяется по размеру, чтобы покрыть большую часть экрана, но некоторые другие подпункты все еще видны снизу.
Я хочу, чтобы мое приложение игнорировало касания других подзонов, когда одно из подзонов "расширяется" подобно этому. Есть ли простой способ достичь этого? Я могу написать код, чтобы справиться с этим, но я надеялся, что там будет более простой встроенный способ.
Ответы
Ответ 1
Надеюсь, что эта помощь...
[[yourSuperView subviews]
makeObjectsPerformSelector:@selector(setUserInteractionEnabled:)
withObject:[NSNumber numberWithBool:FALSE]];
который отключит userInteraction представления немедленного просмотра. Затем дайте userInteraction единственное представление, которое вы хотели
yourTouchableView.setUserInteraction = TRUE;
EDIT:
Кажется, что при отключении iOS userInteraction на родительском представлении не отключается userInteraction на его дочерних элементах. Итак, код выше (я имею в виду один с makeObjectsPerformSelector:
) будет работать только для отключения userInteraction родительского немедленного просмотра.
См. ответ пользователя madewulf, который рекурсивно получает все подзапросы и отключает взаимодействие пользователей со всеми из них. Или, если вам нужно отключить userInteraction этого представления во многих местах проекта, вы можете классифицировать UIView, чтобы добавить эту функцию. Что-то вроде этого будет делать.
@interface UIView (UserInteractionFeatures)
-(void)setRecursiveUserInteraction:(BOOL)value;
@end
@implementation UIView(UserInteractionFeatures)
-(void)setRecursiveUserInteraction:(BOOL)value{
self.userInteractionEnabled = value;
for (UIView *view in [self subviews]) {
[view setRecursiveUserInteraction:value];
}
}
@end
Теперь вы можете позвонить
[yourSuperView setRecursiveUserInteraction:NO];
Также пользователь @lxt предлагает добавить невидимый вид поверх всего представления - это еще один способ сделать это.
Ответ 2
Есть несколько способов сделать это. Вы можете прокручивать все ваши другие подзаголовки и устанавливать userInteractionEnabled = NO
, но это не так идеально, если у вас много других представлений (в конце концов, вам придется впоследствии их переименовать).
Как я делаю это, нужно создать невидимый UIView, чтобы размер всего экрана, который "блокирует" все касания от перехода к другим представлениям. Иногда это буквально невидимо, иногда я могу установить его на черный с альфа-значением 0,3 или около того.
Когда вы расширяете свой основной подзаголовок, чтобы заполнить экран, вы можете добавить этот "блокирующий" UIView за ним (используя insertSubview: belowSubview:
). Когда вы сворачиваете расширенный subview, вы можете удалить невидимый UIView из своей иерархии.
Так что не совсем встроенный, но я считаю самый простой подход. Не уверен, что это было то, о чем вы уже думали, надеюсь, это помогло.
Ответ 3
Остерегайтесь кода, данного здесь решением Кришнабхадры:
[[yourSuperView subviews]makeObjectsPerformSelector:@selector(setUserInteractionEnabled:) withObject:[NSNumber numberWithBool:FALSE]];
Это не будет работать во всех случаях, потому что [subSphereServiceView] дает только прямые подсмотры супервизора. Чтобы заставить его работать, вам придется рекурсивно перебирать все подзоны:
-(void) disableRecursivelyAllSubviews:(UIView *) theView
{
theView.userInteractionEnabled = NO;
for(UIView* subview in [theView subviews])
{
[self disableRecursivelyAllSubviews:subview];
}
}
-(void) disableAllSubviewsOf:(UIView *) theView
{
for(UIView* subview in [theView subviews])
{
[self disableRecursivelyAllSubviews:subview];
}
}
Теперь вызов disableAllSubviewsOf
будет делать то, что вы хотели сделать.
Если у вас есть глубокий стек представлений, решение lxt, вероятно, лучше.
Ответ 4
Я бы сделал это, разместив настраиваемую прозрачную кнопку с тем же фреймом, что и superView
. И затем поверх этой кнопки я бы поставил представление, которое должно принимать пользовательские касания.
Кнопка будет проглатывать все касания, а просмотры позади нее не будут получать никаких событий касания, но просмотр сверху кнопки будет получать штрихи в обычном режиме.
Что-то вроде этого:
- (void)disableTouchesOnView:(UIView *)view {
UIButton *ghostButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, view.frame.size.width, view.frame.size.height)];
[ghostButton setBackgroundColor:[UIColor clearColor]];
ghostButton.tag = 42; // Any random number. Use #define to avoid putting numbers in code.
[view addSubview:ghostButton];
}
И метод включения parentView
.
- (void)enableTouchesOnView:(UIView *)view {
[[view viewWithTag:42] removeFromSuperview];
}
Итак, чтобы отключить все представления в parentViev
позади yourView
, я бы сделал следующее:
YourView *yourView = [[YourView alloc] initWithCustomInitializer];
// It is important to disable touches on the parent view before adding the top most view.
[self disableTouchesOnView:parentView];
[parentView addSubview:yourView];
Ответ 5
Просто parentView.UserInteractionEnabled = NO
выполнит эту работу.
Родительский взгляд будет отключить взаимодействие пользователя во всех подзонах представления. Но включить не поддерживает включение всех подзонов (по умолчанию UIImageView не взаимодействует). Таким образом, простой способ - найти родительское представление и использовать вышеприведенный код, и нет необходимости перебирать все подпункты для выполнения селектора.
Ответ 6
setUserInteractionEnabled = NO
в представлении, которое вы хотите отключить
Ответ 7
Я дам 2 цента этой проблеме.
Итеративно запускайте userInteractionEnabled = false в один конец.
Другой способ - добавить UIView, как показано ниже.
EZEventEater.h
#import <UIKit/UIKit.h>
@interface EZEventEater : UIView
@end
EZEventEater.m
#import "EZEventEater.h"
@implementation EZEventEater
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
self.backgroundColor = [UIColor clearColor];
self.userInteractionEnabled = false;
}
return self;
}
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//EZDEBUG(@"eater touched");
}
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
}
В своем коде вы добавляете представление EZEventEater, чтобы охватить все виды, которые могут заблокировать событие касания.
Всякий раз, когда вы хотите заблокировать сенсорное событие для этих представлений, просто вызовите
eater.userInteractionEnabled = YES;
Надеюсь, что это поможет.
Ответ 8
Для моего приложения, я думаю, будет достаточно отключить навигацию к другим вкладкам приложения (в течение ограниченного времени, пока я делаю некоторую обработку):
self.tabBarController.view.userInteractionEnabled = NO;
Кроме того, я отключил текущий контроллер представления -
self.view.userInteractionEnabled = NO;
(И, кстати, предлагаемые здесь рекурсивные решения имели нечетные эффекты в моем приложении. Отключение, похоже, работает нормально, но повторное включение имеет нечетные эффекты - некоторые из пользовательского интерфейса не были переименованы).
Ответ 9
Добавьте TapGestureRecognizer в свой "фоновый вид" (полупрозрачный, который "вычеркивает" ваш обычный интерфейс) и установите для него "Отменяет прикосновения в представлении" без добавления действия.
let captureTaps = UITapGestureRecognizer()
captureTaps.cancelsTouchesInView = true
dimmedOverlay?.addGestureRecognizer(captureTaps)
Ответ 10
У меня была та же проблема, но вышеупомянутые решения не помогли.
Затем я заметил, что вызов
super.touchesBegan(...)
была проблема.
После удаления это событие обрабатывалось только самым верхним видом.
Я надеюсь, что это поможет кому угодно.