2009-02-20 2 views
6

Ich habe eine UIPickerView, die zu 20% Alpha ausgeblendet wird, wenn sie nicht verwendet wird. Ich möchte, dass der Benutzer den Picker anfassen und wieder einblenden kann.Reagieren auf BerührungenBegan in UIPickerView anstelle von UIView

Ich kann es zur Arbeit bringen, wenn ich eine touchesBegan-Methode in der Hauptansicht einfüge, aber das funktioniert nur, wenn der Benutzer die Ansicht berührt. Ich habe versucht, UIPickerView Sub-Classing und einen TouchesBegan dort, aber es hat nicht funktioniert.

Ich vermute, es ist etwas mit der Responder-Kette zu tun, aber es scheint nicht zu funktionieren.

Antwort

10

Ich habe über eine Woche nach einer Lösung für dieses Problem gesucht. Ich antworte Ihnen, auch wenn Sie Fragen über ein Jahr alt sind, in der Hoffnung, dass dies anderen hilft.

Sorry, wenn meine Sprache nicht sehr technisch ist, aber ich bin ziemlich neu in Objective-C und iPhone Entwicklung.

Subclassing UIpickerView ist der richtige Weg, es zu tun. Aber Sie müssen die - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event Methode überschreiben. Dies ist die Methode, die aufgerufen wird, wenn Sie den Bildschirm berühren und die Ansicht zurückgibt, die auf die Berührung reagiert. Mit anderen Worten die View, deren touchesBegan:withEvent: Methode aufgerufen wird.

Der UIPickerView hat 9 Unteransichten! In der UIPickerView-Klassenimplementierung gibt - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)eventself nicht zurück (dies bedeutet, dass touchesBegan:withEvent:, das Sie in der Unterklasse schreiben, nicht aufgerufen wird), sondern eine Unteransicht, genau die Ansicht bei Index 4 (eine undokumentierte Unterklasse namens UIPickerTable) zurückgibt.

Der Trick ist, die - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event Methode, um zurückzukehren self so haben Sie die Kontrolle über die touchesBegan:withEvent:, touchesMoved:withEvent: und touchesEnded:withEvent: Methoden.

Um bei diesen Methoden die Standardfunktionen von UIPickerView beizubehalten, MÜSSEN Sie sich daran erinnern, sie erneut aufzurufen, jedoch in der Untersicht UIPickerTable.

Ich hoffe, das macht Sinn. Ich kann jetzt keinen Code schreiben, sobald ich zuhause bin, werde ich diese Antwort bearbeiten und etwas Code hinzufügen.

8

Hier ist ein Code, der tut, was Sie wollen:

@interface TouchDetectionView : UIPickerView { 

} 
- (UIView *)getNextResponderView:(NSSet *)touches withEvent:(UIEvent *)event; 
@end 
@implementation TouchDetectionView 

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    UIView * hitTestView = [self getNextResponderView:touches withEvent:event]; 
    [hitTestView touchesBegan:touches withEvent:event]; 
} 

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    UIView * hitTestView = [self getNextResponderView:touches withEvent:event]; 
    [hitTestView touchesMoved:touches withEvent:event]; 
} 

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    UIView * hitTestView = [self getNextResponderView:touches withEvent:event]; 
    [hitTestView touchesEnded:touches withEvent:event]; 
} 

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    UIView * hitTestView = [self getNextResponderView:touches withEvent:event]; 
    [hitTestView touchesCancelled:touches withEvent:event]; 
} 

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event 
{ 
    return self; 
} 

- (UIView *)getNextResponderView:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    UITouch * touch = [touches anyObject]; 
    CGPoint point = [touch locationInView:self]; 
    UIView * hitTestView = [super hitTest:point withEvent:event]; 

    return (hitTestView == self) ? nil : hitTestView; 
} 
+0

Dank arbeitete es funktionierte :) – ArunGJ

+1

dieser Code scheint zu funktionieren, es sei denn, eine Berührung tritt auf dem Rahmen, den Picker Rad unmittelbar umgibt. Das scheint eine endlose Schleife von Aufrufen der getNextResponderView zu verursachen: withEvent: method. – pistachionut

+1

ya ich verhinderte es, indem ich nil anstelle von hitTestView von getNextResponderView zurückgab: withEvent: wenn ich das umgebende Rad berührte. – ArunGJ

1

sehr hilfreich Beide oben genannten Antworten waren, aber ich habe eine UIPickerView innerhalb eines UIScrollView verschachtelt. Ich mache auch fortlaufend Rendering an anderer Stelle auf dem Bildschirm, während die GUI vorhanden ist. Das Problem besteht darin, dass UIPickerView nicht vollständig aktualisiert wird, wenn: eine nicht ausgewählte Zeile angetippt wird, die Auswahl so verschoben wird, dass zwei Zeilen den Auswahlbereich überspreizen, oder wenn eine Zeile gezogen wird, der Finger jedoch außerhalb von UIPickerView verschoben wird. Erst wenn UIScrollView verschoben wird, wird der Picker sofort aktualisiert. Dieses Ergebnis ist hässlich.

Die Ursache des Problems: mein kontinuierliches Rendering hielt die UIPickerView-Animation davon ab, die CPU-Zyklen zu erhalten, die zum Beenden benötigt wurden, um somit die korrekte, aktuelle Auswahl anzuzeigen. Meine Lösung - was funktioniert - war folgendes: In der UIPickerView-Datei touchesEnded:withEvent: führe etwas aus, um mein Rendering für eine kurze Zeit anzuhalten. Hier ist der Code:

#import "SubUIPickerView.h" 

@implementation SubUIPickerView 

- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event 
{ 
    [pickerTable touchesBegan:touches withEvent:event]; 
} 

- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event 
{ 
    [pickerTable touchesMoved:touches withEvent:event]; 
} 

- (void) touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event 
{ 
    [singleton set_secondsPauseRendering:0.5f]; // <-- my code to pause rendering 

    [pickerTable touchesEnded:touches withEvent:event]; 
} 

- (void) touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event 
{ 
    [pickerTable touchesCancelled:touches withEvent:event]; 
} 

- (UIView*) hitTest:(CGPoint)point withEvent:(UIEvent*)event 
{ 
    if (CGRectContainsPoint(self.bounds, point)) 
    { 
     if (pickerTable == nil) 
     { 
      int nSubviews = self.subviews.count; 
      for (int i = 0; i < nSubviews; ++i) 
      { 
       UIView* view = (UIView*) [self.subviews objectAtIndex:i]; 
       if ([view isKindOfClass:NSClassFromString(@"UIPickerTable")]) 
       { 
        pickerTable = (UIPickerTable*) view; 
        break; 
       } 
      } 
     } 
     return self; // i.e., *WE* will respond to the hit and pass it to UIPickerTable, above. 
    } 
    return [super hitTest:point withEvent:event]; 
} 

@end 

und dann der Kopf, SubUIPickerView.h:

@class UIPickerTable; 

@interface SubUIPickerView : UIPickerView 
{ 
    UIPickerTable* pickerTable; 
} 

@end 

Wie ich schon sagte, das funktioniert.Das Rendering wird für weitere 1/2 Sekunde angehalten (es wird bereits angehalten, wenn Sie UIScrollView verschieben), wodurch die UIPickerView-Animation beendet werden kann. Die Verwendung von NSClassFromString() bedeutet, dass Sie keine undokumentierten APIs verwenden. Es war nicht nötig, mit der Responder-Kette zu chatten. Danke an checcco und Tylerc230, die mir geholfen haben, meine eigene Lösung zu finden!

+0

Dies funktioniert nicht mehr mit UIPickerView von iOS 8. – MatthiasC

+0

@MatthiasC Weißt du, warum es nicht mehr funktioniert? – stonedauwg

+0

Diese Beiträge über UIPickerView sind wirklich alt. Es war damals neu und flakig. Apple hat es wahrscheinlich (hoffentlich) komplett neu implementiert! – electromaggot

0

Set canCancelContentTouches und delayscontenttouches der Eltern im Hinblick auf NO, die für mich