2013-03-17 17 views
27

Ich habe eine UIView (die 'Containeransicht'), die mehrere 'Unteransichten' enthält. Ich möchte der Containeransicht einen UITapGestureRecognizer hinzufügen, sodass dieser aktiviert wird, wenn ich die Region innerhalb der Containeransicht, aber außerhalb der Teilansichten berühre.Subviews von UIGestureRecognizer ausschließen

Im Moment wird durch Berühren einer beliebigen Stelle in der Containeransicht, einschließlich innerhalb der Teilansichten, der Gestenerkenner aktiviert.

Die Implementierung sieht ungefähr wie folgt aus: In der Steuerung:

ContainerView *containerView = [[ContainerView alloc] initWithSubViews:array]; 
UITapGestureRecognizer *tap = [UITapGestureRecognizer alloc] initWithTarget:self action:@selector(someSelector)]; 
[containerView addGestureRecognizer:tap]; 
[self.view addSubView:containerView]; 

In ContainerView.m

-(id)initWithSubviews:(NSArray *)array { 
    for (subView *s in array) { 
     [self addSubView:s]; 
    } 
    return self; 
} 

Ich denke, das Problem tritt auf, weil die Gestenerkenner hinzugefügt wird, nachdem die Subviews sind. Wenn das wahr ist, dann würde die Lösung die initWithSubViews-Methode in zwei separate brechen müssen, die ich lieber vermeiden würde.

Danke

Antwort

9

iOS 6 stellt eine große neue Funktion, die genau dieses Problem löst - ein UIView (subview) nicht von gestureRecognizerShouldBegin: zurückkehren (Geste-Erkennungs angebracht ein superview). Tatsächlich ist dies der Standard für einige UIView-Unterklassen in Bezug auf einige Gestenerkenner bereits (z. B. ein UIButton in Bezug auf einen UITapGestureRecognizer, der an eine Superview angehängt ist).

Siehe mein Buch zu diesem Thema: http://www.apeth.com/iOSBook/ch18.html#_gesture_recognizers

0

Wenn Sie UITapGestureRecognizer für ContainerView hinzugefügt, es mit der ganzen ContainerView reagieren soll. Es macht nichts gegen seine Untersichten.

Überprüfen Sie den Gestenstandort, wenn er sich in Ihrer Unteransicht befindet, überspringen Sie einfach die Gestenaktionen.

- (void) tapGestureHandler:(UIGestureRecognizer *) gestureRecognizer { 


    CGPoint tapPoint = [gestureRecognizer locationInView:nil]; 

    //check your tapPoint contains ur subview frame, skip.else do ur actions 
} 
+0

Dies ist teuer und haarig, wenn viele Subviews überprüft werden müssen. – CodaFi

+0

yup..ich sehe .. ich sehe keine anderen guten Lösungen .. wenn Sie haben, fühlen Sie sich frei zu teilen .. :) –

0

ZUSÄTZLICH:

ich besser von etwas gerade dachte.

in Ihrem Handler

-(void)tapGestureHandler:(UITapGestureHandler)gesture 

überprüfen, ob gesture.view die Superview ist. wird die Unteransicht zurückgegeben, wenn auf Unteransichten geklickt wird.

============================================== ======

Ich würde vorschlagen, innerhalb der Superview zu überschreiben.

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event 

ist dies, wenn eine Geste

die Antwort auf diese Frage zu sehen, um zu sehen, wie es standardmäßig verhält sich innerhalb einer Ansicht fällt bestimmen genannt.

Event handling for iOS - how hitTest:withEvent: and pointInside:withEvent: are related?

Sie können prüfen, ob der Punkt in einem seiner Subviews ist. Wenn ja, gib nil zurück, sonst melde dich zurück.

OR

in jedem der Subviews, fügen Sie ein tapgesture Erkenner, der nichts tut. Der Gestenerkenner einer Unteransicht wird standardmäßig den Gestenerkenner seiner Superansicht löschen. Ich würde jedoch den Speicherbedarf im Auge behalten, wenn es viele Unteransichten gibt.

+0

Leider glaube ich nicht, dass dies funktioniert. Laut den Dokumenten gibt Ihnen "Gesten.Ansicht" die Ansicht "Die Ansicht, in der der Gestenerkenner angebracht ist". Dies gibt die gesamte Containeransicht und nicht die Unteransicht an. Die zweite Option sieht vielversprechend aus, ich werde es versuchen. –

+0

Großartig, ich habe es mit der Methode hitTest: withEvent funktioniert. Siehe Beitrag unten. –

11

schaffte ich es zum Laufen bringen die von folgenden Aktionen ausführen:

UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureHandler:)]; 

// ... 

-(void) tapGestureHandler:(UITapGestureRecognizer *)sender { 
    CGPoint point = [sender locationInView:sender.view]; 
    UIView *viewTouched = [sender.view hitTest:point withEvent:nil]; 
    if ([viewTouched isKindOfClass:[ThingIDontWantTouched class]]) { 
     // Do nothing; 
    } else { 
     // respond to touch action 
    } 
} 
37

habe ich die einfache Art und Weise unten. Es funktioniert genau! Implementieren

UIGestureRecognizerDelegate Funktion, nehmen nur touchs auf Superview, akzeptieren nicht touchs auf Subviews:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch 
{ 
    if (touch.view != _mySuperView) { // accept only touchs on superview, not accept touchs on subviews 
     return NO; 
    } 

    return YES; 
} 
4

Denken Sie daran, hinzufügen und die delegierte Methode -

In Ihrem UIViewController der .h-Datei enthalten dieser Delegierte

@interface YourViewController: UIViewController<UIGestureRecogniserDelegate> 

Dann wo Sie yo erstellen ur tapGesture Objekt, (beispielsweise innerhalb von viewDidLoad)

UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(actionMethodYouWantToHappenOnTap)]; 

    tap.delegate = self; //Remember to set delegate! Otherwise the delegate method won't get called. 

    [self.view addGestureRecognizer:tap]; 

Erinnern an die Delegatmethode zum Tippen auf tap abzufeuern wird nun tap.delegate = self; dann die Delegatmethode einzustellen.

Innerhalb dieser Methode, die Sie behandeln, wenn Sie den Hahn Gestenerkennung möchten verwendet werden, in meinem Code wollte ich es einen Wasserhahn ignorieren, wenn eine bestimmte subview

-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{ 

    if (!mySubview.hidden){ 
    return NO; //This fired if said subview was visible, though whatever the condition of where and when you want tap to work, can be handled within this delegate method. 
    } 

    return YES; 
} 

ich dies jemand hilft sonst Hoffnung sichtbar war mit dem gleichen Problem. Die Erinnerung daran, die Delegate-Methode, die ich gefunden habe, festzulegen, war etwas, das leicht übersehen wurde.

Prost

2

Viele Antworten, Hinzufügen einer anderen alternativen Lösung. Initialisiere die Ansicht Tag der Subviews Sie möchten nicht berührt empfangen als 1 und wie folgt vorgehen:

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)]; 
    tap.delegate = self; 
    [self.view addGestureRecognizer:tap]; 
} 

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch 
{ 
    if (touch.view.tag == 1) { 
     return NO; 
    } 
    return YES; 
} 

-(void)handleTap:(id)sender 
{ 
//Handle tap... 
} 

Auf diese Weise wird die Berührungsgeste nur von den Ansichten empfangen werden Sie es benötigen aus.