it-swarm.com.de

UITableView in UIScrollView empfängt nach dem Scrollen nicht den ersten Tipp

Kurz

Ich habe ein Problem mit einem UITableView in einem UIScrollView. Wenn ich das externe scrollView scrolle, erhält das table das willSelect/didSelect-Ereignis nicht bei der ersten Berührung, sondern bei der zweiten Berührung. Noch seltsamer ist, dass die Zelle selbst die Berührungen und den hervorgehobenen Status erhält, selbst wenn delegate dies nicht tut.

Ausführliche Erklärung

Meine Ansichtshierarchie:

UIView
  - UIScrollView  (outerscroll)
      - Some other views and buttons
      - UITableView (tableView)

In der Scroll-Ansicht habe ich einige zusätzliche Ansichten, die dynamisch erweitert/geschlossen werden. Die Tabellensicht muss oben zusammen mit einigen anderen Elementen der Ansicht "repariert" werden. Deshalb habe ich dieses Layout erstellt, das es mir ermöglicht, Elemente auf ähnliche Weise zu verschieben, als es Apple durch Transformationen empfiehlt Die Schriftrolle passiert.

Die Tabellenansicht wird mit einem Übersetzungseffekt transformiert, wenn sich der Outerscroll wie folgt bewegt:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    if (scrollView == self.outerScrollView) {

        CGFloat tableOffset = scrollView.contentOffset.y - self.fixedHeaderFrame.Origin.y;
        if (tableOffset > 0) {
            self.tableView.contentOffset = CGPointMake(0, tableOffset);
            self.tableView.transform = CGAffineTransformMakeTranslation(0, tableOffset);
        }
        else {
            self.tableView.contentOffset = CGPointMake(0, 0);
            self.tableView.transform = CGAffineTransformIdentity;
        }

        // Other similar transformations are done here, but not involving the table

}

Wenn ich in meiner Zelle diese Methoden implementiere:

- (void)setSelected:(BOOL)selected {
    [super setSelected:selected];
    if (selected) {
        NSLog(@"selected");
    }
}

- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated
{
    [super setHighlighted:highlighted animated:animated];
    if (highlighted) {
        NSLog(@"highlighted");
    }
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesBegan:touches withEvent:event];
    NSLog(@"touchesBegan");
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesEnded:touches withEvent:event];
    NSLog(@"touchesEnded");
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesCancelled:touches withEvent:event];
    NSLog(@"touchesCancelled");
}

Y kann diese Ausgabe sehen, wenn ein Fehler auftritt (erster Tipp):

2014-02-10 13:04:40.940 MyOrderApp[5588:70b] highlighted 
2014-02-10 13:04:40.940 MyOrderApp[5588:70b] touchesBegan 
2014-02-10 13:04:40.978 MyOrderApp[5588:70b] touchesEnded

Und dieses, wenn es funktioniert (zweiter Tipp):

2014-02-10 13:05:30.359 MyOrderApp[5588:70b] highlighted 
2014-02-10 13:05:30.360 MyOrderApp[5588:70b] touchesBegan 
2014-02-10 13:05:30.487 MyOrderApp[5588:70b] touchesEnded 
2014-02-10 13:05:30.498 MyOrderApp[5588:70b] expanded

Zwischen dem ersten und dem zweiten Tap werden keine anderen Frame-Änderungen, Animationen oder andere Interaktionen zwischen den Ansichten vorgenommen. Nur beim Scrollen in großen Mengen tritt der Fehler auf, aber bei Scrollen von wenigen Pixeln funktioniert alles wie erwartet.

Ich habe auch experimentiert, einige Eigenschaften zu ändern, aber ohne Glück. Einige Dinge, die ich gemacht habe:

  • Entfernen Sie userInteractionEnabled aus anderen Ansichten als dem Bildlauf und der Tabelle
  • Fügen Sie setNeedsLayout in der Tabelle einen Aufruf hinzu, scrollen Sie und zeigen Sie die Hauptansicht an, wenn scrollViewDidScroll auftritt.
  • Entferne die Transformationen aus der Tabelle (passiert immer noch)

Ich habe einige Kommentare über das unerwartete Verhalten der Einbettung von UITableViews in UIScrollViews gesehen, aber ich kann eine solche Warnung nicht in der offiziellen Dokumentation von Apple sehen, daher erwarte ich, dass sie funktioniert. 

Die App ist nur iOS7 +.

Fragen

Hat jemand ähnliche Probleme erlebt? Warum ist das und wie kann ich es lösen ? Ich denke, ich könnte die Abgriffsgeste in der Zelle abfangen und mit einem benutzerdefinierten Delegierten oder ähnlichem übergeben, aber Ich möchte, dass die Tabelle die richtigen Ereignisse empfängt und meine UITableViewDelegate empfängt sie erwartungsgemäß.

Aktualisierung

  • Ich habe versucht, die Wiederverwendung von Zellen wie in einem Kommentar vorgeschlagen zu deaktivieren, aber es geschieht immer noch auf dieselbe Weise.
30

Aus Apple-Dokumentation sollten Sie keine UITableViewin einer UIScrollView einbetten.

Wichtig: Sie sollten keine UIWebView- oder UITableView-Objekte in .__ einbetten. UIScrollView-Objekte. In diesem Fall kann unerwartetes Verhalten auftreten weil Berührungsereignisse für die beiden Objekte falsch miteinander verwechselt werden können abgewickelt.

Ihr Problem hängt wirklich davon ab, was Ihre UIScrollView tut.

Wenn es jedoch nur darum geht, die Tabellenansicht bei Bedarf auszublenden (das war mein Fall), können Sie die Variable UITableView einfach in ihre Übersicht verschieben.

Ich habe hier ein kleines Beispiel geschrieben: https://github.com/rvirin/SoundCloud/

22
Rémy Virin

lassen Sie die scrollEnabled-Eigenschaft des inneren UITableView als YES festgelegt. Dies lässt den inneren UITableView wissen, wie er mit der Scroll-bezogenen Berührung des UIScrollView korrekt umgeht.

19
Tom Abraham

Ich bin auf dieses Problem gestoßen und habe eine Lösung gefunden !! 

Sie müssen delaysTouchesBegan in Ihrer Bildlaufansicht auf "true" setzen, damit die Bildlaufansicht die fehlgeschlagene Bildlauf-Geste (d. H. Das Tippen) an ihre Kinder sendet. 

var delaysTouchesBegan: Bool -Ein boolescher Wert, der bestimmt, ob der Empfänger das Senden von Berührungen in einer Anfangsphase verzögert.

Wenn der Wert der Eigenschaft YES ist, wird die Lieferung von .__ im Fenster ausgesetzt. Berühren Sie Objekte in der UITouchPhaseBegan-Phase zur Ansicht. Wenn der Der Gestenerkenner erkennt daraufhin seine Geste, diese Berührung Objekte werden verworfen. Wenn die Gestenerkennung jedoch nicht Wenn die Geste erkannt wird, liefert das Fenster diese Objekte an die Ansicht in einem touchesBegan: withEvent: message (und möglicherweise einer Folge touchesMoved: withEvent: message, um ihn über die aktuellen -Orte der Touches zu informieren).

https://developer.Apple.com/library/ios/documentation/UIKit/Reference/UIGestureRecognizer_Class/index.html#//Apple_ref/occ/instp/UIGestureRecognizer/delaysTouchesBegan

Aber es gibt einen Haken ... es funktioniert nicht, wenn Sie es direkt in der Bildlaufansicht machen!

// Does NOT work
self.myScrollview.delaysTouchesBegan = true

Anscheinend ist dies ein iOS-Fehler, bei dem die Einstellung dieser Eigenschaft nicht funktioniert (danke Apple). Es gibt jedoch eine einfache Problemumgehung: Legen Sie die Eigenschaft direkt in der Pan-Geste der Bildlaufansicht fest. Klar, das hat für mich perfekt funktioniert:

// This works!!
self.myScrollview.panGestureRecognizer.delaysTouchesBegan = true
13
Oren

Es scheint, dass Ihre UiTableView Ihr Tippen nicht erkennt. Haben Sie versucht, das zu benutzen:

- (BOOL)gestureRecognizer:(UIPanGestureRecognizer *)gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer:(UISwipeGestureRecognizer             *)otherGestureRecognizer
{
    if ([otherGestureRecognizer.view isKindOfClass:[UITableView class]]) {
        return YES;
    }
    return NO;
}

Hinweis von Apple: 

wird aufgerufen, wenn die Erkennung von gestureRecognizer oder otherGestureRecognizer durch den anderen blockiert wird. Geben Sie JA zurück, damit beide gleichzeitig erkennen können. Die Standardimplementierung gibt NEIN zurück (standardmäßig können keine zwei Gesten gleichzeitig erkannt werden).

hinweis: Die Rückgabe von YES garantiert garantiert die gleichzeitige Erkennung. Die Rückgabe von NEIN garantiert nicht die gleichzeitige Erkennung, da der Delegierte der anderen Geste JA zurückgeben kann

Hoffe das wird helfen.

3
Nicolas Bonnet

Gestenerkennung funktioniert für zwei eingebettete Bildlaufansichten oder Unterklassen nicht ordnungsgemäß.

Versuchen Sie eine Problemumgehung:

  1. Verwenden Sie transparent, benutzerdefiniert und überlagern Sie alles in der Zelle UIButton mit dem richtigen Tag oder der Unterklasse UIButton. Fügen Sie eine Indexpfad-Eigenschaft hinzu und überschreiben Sie sie jedes Mal in einer wiederverwendeten Zelle. 

  2. Fügen Sie diese Schaltfläche als Eigenschaft zu Ihrer benutzerdefinierten Zelle hinzu.

  3. Fügen Sie ein Ziel für die gewünschte UIControlEvent (eine oder mehrere) hinzu, die auf Ihre UITableViewDelegate-Übernahmeklasse verweist.

  4. Deaktivieren Sie die Auswahl in IB und verwalten Sie die Auswahl manuell aus dem Code.

Diese Lösung erfordert bei Einzel-/Mehrfachselektionen Aufmerksamkeit.

3
Wladek Surala

Ich habe eine UITableView festgestellt, bei der scrollEnabled in einem UIScrollView in älterem Code NEIN ist. Ich war nicht in der Lage, die vorhandene Hierarchie auf einfache Weise zu ändern oder das Scrollen zu aktivieren. Ich habe jedoch die folgende Problemumgehung für das Problem mit dem ersten Tippen gefunden:

@interface YourOwnTableView : UITableView
@end

@implementation YourOwnTableView

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {

    [super touchesCancelled:touches withEvent:event];

    // Note that this is a hack and it can stop working at some point.
    // Looks like a table view with scrollEnabled being NO does not handle cancellation cleanly,
    // so let's repeat begin/end touch sequence here hoping it'll reset its own internal state properly
    // but won't trigger cell selection (the touch passed is in its cancelled phase, perhaps there is a part
    // of code inside which actually checks it)
    [super touchesBegan:touches withEvent:event];
    [super touchesEnded:touches withEvent:event];
}

@end

Auch dies ist nur eine Problemlösung, die in meinem speziellen Fall funktioniert. Eine Tabellenansicht in einer Bildlaufansicht ist immer noch eine falsche Sache.

2
aleh

Ich habe das gleiche Problem mit geschachtelten UITableView und habe dafür eine Problemumgehung gefunden:

innerTableView.scrollEnabled = YES;
innerTableView.alwaysBounceVertical = NO;

Sie müssen die Höhe der inneren Tabellenansicht so einstellen, dass sie mit der Gesamthöhe ihrer Zellen übereinstimmt, sodass beim Scrollen durch die äußere Ansicht kein Bildlauf ausgeführt wird.

Hoffe das hilft.

1
Duc Minh Trinh

Mein Fehler war die Implementierung der Delegat-Methode:

- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath

anstelle derjenigen, die ich implementieren wollte: 

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

Daher wird nur aufgerufen, wenn die zweite Zelle angezapft wird, denn dann würde die erste Zelle de ausgewählt. Dummer Fehler, der mit Hilfe von Autocomplete gemacht wurde. Nur ein Gedanke für die von Ihnen, die hier möglicherweise wandern, ohne zu merken, dass Sie den gleichen Fehler gemacht haben.

1
LunaCodeGirl

Ich würde empfehlen, nach Optionen zu suchen, z. B., dass Ihre Zelle nicht hervorgehoben wird, wenn Sie die äußere Bildlaufansicht scrollen, was sehr einfach zu handhaben ist und die empfohlene Methode ist. Sie können dies einfach tun, indem Sie einen booleschen Wert nehmen und ihn in der folgenden Methode umschalten

- (void)scrollViewDidScroll:(UIScrollView *)scrollView 
1
Rajesh

Die Bildlaufansicht versucht herauszufinden, ob der Benutzer einen Bildlauf beabsichtigt oder nicht, daher wird die anfängliche Berührung absichtlich verzögert. Sie können dies deaktivieren, indem Sie delaysContentTouches auf NO setzen.

1
Stepan Hruda
  1. Legen Sie einen UIButton über Ihre UITableViewCell und erstellen Sie den Ausgang als "btnRowSelect".
  2. Fügen Sie in Ihrem View-Controller diesen Code in cellForRowAtIndexPath ein

    cell.btnRowSelect.tag = indexPath.row
    cell.btnRowSelect.addTarget(self, action: Selector("rowSelect:"), forControlEvents: .TouchUpInside)
    
  3. Fügen Sie diese Funktion Ihrem viewController hinzu.

    func rowSelect (sender:UIButton) {
    // "sendet.tag" give you the selected row 
    // do whatever you want to do in didSelectRowAtIndexPath
    }
    

Diese Funktion "rowSelect" funktioniert wie didSelectRowAtIndexPath, wobei Sie erhalten die Zeile "indexPath.row" als "sender.tag"

0
shubham

Wenn es die Touch-Table-Ansicht ist, funktioniert es einwandfrei. auch mit Scroll-Ansicht im selben View-Controller.

tableview.scrollEnabled = true;
0
Ravi H Malviya

Wie andere Antworten sagen, sollten Sie eine Tabellenansicht nicht in eine Bildlaufansicht einfügen. Eine UITableView erbt ohnehin von UIScrollView. Ich denke, da werden die Dinge verwirrend. Was ich in dieser Situation immer tue, ist:

1) Unterklasse UITableViewController und füge eine Eigenschaft UIView * headView hinzu.

2) Erstellen Sie im übergeordneten UIViewController alle Top-Objekte in einem UIView-Container

3) Initialisieren Sie Ihr benutzerdefiniertes UITableView und fügen Sie die Ansicht des tableView zur vollen Größe des View-Controllers hinzu

[self.view addSubview: self.myTableView.view];

4) Stellen Sie das headView als Ihre UIView-Gubbins ein

self.tableView.headView = myHeadViewGubbins.

5) In der tableViewController-Methode

-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger *)section;

Tun:

if ( section == 0 ) {
    return self.headView;
}

Jetzt haben Sie eine Tabellenansicht mit einem Bündel anderen Kräuselern oben.

Genießen!

0
Martin

Ich habe das gleiche Problem, dann beziehen Sie sich auf "Verschachteln von Scroll-Ansichten", wie Lxx sagte.

https://developer.Apple.com/library/ios/documentation/WindowsViews/Conceptual/UIScrollView_pg/NestedScrollViews/NestedScrollViews.html

Ein Beispiel für das Scrollen in Querrichtung finden Sie in der Anwendung "Aktien". Die Draufsicht ist eine Tabellenansicht, aber die Unteransicht ist eine horizontale Bildlaufansicht, die im Paging-Modus konfiguriert ist. Während zwei der drei Unteransichten benutzerdefinierte Ansichten sind, ist die dritte Ansicht (die die Nachrichtenartikel enthält) eine UITableView (eine Unterklasse von UIScrollView), die eine Unteransicht der horizontalen Bildlaufansicht ist. Nachdem Sie horizontal zur Nachrichtenansicht gescrollt haben, können Sie den Inhalt vertikal scrollen.

Es ist Arbeit

0
Davin Kao