Как отключить сенсорный ввод для всех видов, кроме самого верхнего вида?

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

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

10 ответов


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

[[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 о добавлении невидимого представления поверх всех представлений - это еще один способ сделать это..


есть несколько способов сделать это. Вы можете перебирать все свои другие подвиды и устанавливать userInteractionEnabled = NO, но это не идеально, если у вас есть много других взглядов (вы, в конце концов, должны впоследствии переименовать их все).

способ, которым я это делаю, - создать невидимый UIView, размер всего экрана, который "блокирует" все прикосновения от перехода к другим представлениям. Иногда это буквально невидимо, иногда я могу установить его в черный с Альфой значение 0.3 или около того.

когда вы расширяете свой основной подзор, чтобы заполнить экран, вы можете добавить этот "блокирующий" UIView позади него (используя insertSubview: belowSubview:). При сворачивании развернутого подвида можно удалить невидимый UIView из иерархии.

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


остерегайтесь кода, данного здесь Кришнабхадрой в качестве решения:

[[yourSuperView subviews]makeObjectsPerformSelector:@selector(setUserInteractionEnabled:) withObject:[NSNumber numberWithBool:FALSE]];

Это не будет работать во всех случаях, потому что [yoursuperview subviews] дает только прямые подвиды супервизора. Чтобы заставить его работать, вам придется рекурсивно перебирать все подвиды:

-(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, вероятно, лучше.


Я бы сделал это, поставив пользовательская прозрачная кнопка С тем же кадром, что и 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];

просто parentView.UserInteractionEnabled = NO сделает работу. Родительский вид будет отключить взаимодействие с пользователем во всех подвидах представления. Но!--2-->включить это не включить все подвиды (по умолчанию UIImageView не является интерактивным). Таким образом, простой способ-найти родительское представление и использовать код выше, и нет необходимости повторять все подвиды для выполнения селектора.


Я дам свои 2 цента на эту проблему. Итеративно запустите userInteractionEnabled = false это один из способов. Другим способом будет добавить UIView, как показано ниже.

EZEventEater.h

#import <UIKit/UIKit.h>
@interface EZEventEater : UIView
@end

EZEventEater.м

#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, чтобы охватить все представления, которые могут блокировать событие касания. Всякий раз, когда вы хотите заблокировать событие touch для этих представлений, просто вызовите

eater.userInteractionEnabled = YES;

надеюсь, что это полезно.


добавьте TapGestureRecognizer в свой " фоновый вид "(полупрозрачный, который" сереет "ваш обычный интерфейс) и установите его в" отменяет касания в поле зрения", без добавления действия.

let captureTaps = UITapGestureRecognizer()
captureTaps.cancelsTouchesInView = true
dimmedOverlay?.addGestureRecognizer(captureTaps)

setUserInteractionEnabled = NO в представлении, которое вы хотите отключить


для моего приложения, я думаю, будет достаточно отключить навигацию на другие вкладки приложения (в течение ограниченного времени, пока я делаю некоторую обработку):

self.tabBarController.view.userInteractionEnabled = NO;

кроме того, я отключил текущий контроллер вида--

self.view.userInteractionEnabled = NO;

(и, кстати, рекурсивные решения, предложенные здесь, имели странные эффекты в моем приложении. Отключение, похоже, работает нормально,но повторное включение имеет странные эффекты - некоторые из UI не были переименованы).


У меня была такая же проблема, но вышеперечисленные решения не помогли. Затем я заметил, что вызов super.touchesBegan(...) была проблема. После удаления этого событие обрабатывалось только самым верхним представлением.

Я надеюсь, что это поможет кому-нибудь.