Pytanie UITableViewCell został pominięty w łańcuchu respondentów


Próbuję wywołać zdarzenie w widoku podrzędnym UITableViewCelli pozwólmy mu spętać łańcuch reakcji i być obsługiwanym przez zwyczaj UITableViewCell podklasa.

Gruntownie:

SomeView.m (który jest podzbiorem UITableViewCell)

[self.button addTarget:nil action:@selector(someAction:) events:UIControlEventTouchUpInside]

SomeCustomCell.m

- (void)someAction:(id)sender {
     NSLog(@"cool, the event bubbled up to the cell");
}

Aby sprawdzić, dlaczego to nie zadziałało, dodałem someAction: Metoda w ViewController i ViewController jest tym, który kończy obsługę zdarzenia, które pęcznieje z podglądu komórki widoku tabeli, nawet jeśli komórka powinna go obsłużyć. Sprawdziłem, czy komórka znajduje się w łańcuchu respondentów i zweryfikowałem, że wszelkie widoki na łańcuchu respondera zarówno powyżej, jak i poniżej komórki będą odpowiadać na wydarzenie, jeśli wdrożą someAction: metoda.

Co tu się dzieje?

Oto projekt, który to pokazuje https://github.com/keithnorm/ResponderChainTest Czy to jakoś to oczekiwane zachowanie? Nie znalazłem żadnej dokumentacji stwierdzającej, że UITableViewCell są traktowane inaczej niż inni użytkownicy UIResponder.


11
2018-01-24 07:30


pochodzenie


To dziwne! Znalazłem łańcuch odpowiadający:ContentView->UITableViewCellContentView->UITableViewCellScrollView->TableCell->UITableViewWrapperView->UITableView->View->ViewController->UIWindow->UIApplication->AppDelegate. Uważam, że przez UIResponder * res = sender ; while (res) { res = [res nextResponder] ; NSLog(@"%@", [res class]) ; }. Pójdę za pytaniem. - KudoCC
Tak, wydaje się, że to powinno zadziałać, prawda? Dziękuję za sprawdzenie tego i potwierdzenie, że również ci się wydaje dziwne :) - Keith Norman
Tak, pobieram twój projekt i oczekuję, że powinien działać, ale się nie udało. Też myliłem się, dlaczego to pomija TableCell. - KudoCC
Więc twoim celem jest po prostu wywołanie metody customEventFired: w TableCell. dobrze? - Vaisakh
Chcę, aby zdarzenie zostało uruchomione w wydziale, ale zostanie przechwycone przez TableCell. - Keith Norman


Odpowiedzi:


Komórka wydaje się prosić o jej widok tabeli o pozwolenie. Aby to zmienić, możesz oczywiście nadpisać

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
    return [self respondsToSelector:action];
}

Swift 3:

override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
    return self.responds(to: action)
}

8
2018-06-21 17:17



Mogę potwierdzić, że to działa, chociaż nie jestem pewien "Komórka wydaje się prosić o jej widok tabeli o pozwolenie" jest właściwym wytłumaczeniem tego zachowania. Co ma z tym wspólnego widok tabeli? Czy to gdzieś dokumentuje? - Ole Begemann
Widok tabeli pyta delegata -tableView: canPerformAction: forRowAtIndexPath: withSender :, ale tylko wtedy, gdy są one kopiowane: lub wklej: :). Ta część jest udokumentowana. I to jest powód, dla którego łańcuch respondentów nie działa zgodnie z oczekiwaniami: komórka przejmuje kontrolę nad działaniem, aby widok tabeli mógł delegować sprawdzanie poprawności menu. - nschmidt
Interesujące, dziękuję za odpowiedź! Zaktualizowałem mój przykładowy projekt na github.com/keithnorm/ResponderChainTest aby pokazać, że to rzeczywiście działa. - Keith Norman


Doszedłem do wniosku, że jest to błąd lub nieudokumentowane zamierzone zachowanie. W każdym razie udało mi się to naprawić, reagując na zdarzenie w wywiadzie, a następnie ręcznie propagując komunikat w łańcuchu respondentów. Coś jak:

- (void)customEventFired:(id)sender {
  UIResponder *nextResponder = self.nextResponder;
  while (nextResponder) {
    if ([nextResponder respondsToSelector:@selector(customEventFired:)]) {
      [nextResponder performSelector:@selector(customEventFired:) withObject:sender];
      break;
    }
    nextResponder = nextResponder.nextResponder;
  }
}

Zaktualizowałem również mój projekt demonstracyjny, aby pokazać, w jaki sposób używam tej "poprawki" https://github.com/keithnorm/ResponderChainTest.

Wciąż cieszę się z wszelkich innych pomysłów, jeśli ktoś to wymyśli, ale to jest najlepsze, co mam na razie.


1
2018-01-24 22:03



Dzięki, działa jak urok. - Sebastian Boldt


Możesz zmienić kod w widoku.m jako

      [button addTarget:nil action:@selector(customEventFired:) forControlEvents:(1 << 24)];

do

      [button addTarget:cell action:@selector(customEventFired:) forControlEvents:(1 << 24)];

0
2018-01-24 08:41



Mógłbym, gdyby wyekspozycja miała odniesienie do jej komórki macierzystej, ale to także przerywa uniezależnianie, które próbuję utrzymać. Wywiad powinien raczej nie wiedzieć o swoich superwiadach, IMO. - Keith Norman


rób jak to

    @implementation ContentView

   // uncomment this to see event caught by the cell's subview

  - (id)initWithFrame:(CGRect)frame
 {
     self = [super initWithFrame:frame];
    if(self)
   {

    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    [button setTitle:@"Click" forState:UIControlStateNormal];
    [button setBackgroundColor:[UIColor blueColor]];
    [button addTarget:self action:@selector(customEventFired:) forControlEvents:UIControlEventTouchUpInside];
    button.frame = CGRectMake(4, 5, 100, 44);
    [self addSubview:button];
  }

    return self;
}

 - (void)customEventFired:(id)sender
{
     UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Event Triggered in cell subview" message:@"so far so good..." delegate:nil cancelButtonTitle:@"cancel" otherButtonTitles:nil, nil];
    [alertView show];
 }

@end

teraz customEventFired: metoda zostanie wywołana


0
2018-01-24 07:58



Dzięki, ale to, co chcę zrobić, to skorzystać z sieci responderów. Moja komórka nie ma bezpośredniego dostępu do przycisku, tak jak robi to twój przykład, i chcę zachować to w ten sposób, aby oddzielić te obiekty. Punkt jest zdarzeniem wywoływanym w wyglądzie, który teoretycznie powinien zostać wysłany do superwizji. To jak delegowanie / bulgotanie wydarzeń w JavaScript. - Keith Norman
oky przepraszam, że nie ściągnąłem twojego kodu, właśnie wysłałem moją odpowiedź bezpośrednio, więc mam teraz, nie dodawaj przycisku w samej treści, a potem dostań odpowiedź do wydziału komórki - Shankar BS
zobacz zaktualizowaną odpowiedź - Shankar BS


Myślę, że to jest najprostsze rozwiązanie. Jeśli nie określisz celu, zdarzenie spowoduje automatyczne zbuforowanie łańcucha respondentów.

[[UIApplication sharedApplication]sendAction:@selector(customAction:) to:nil from:self forEvent:UIEventTypeTouches];

0
2018-06-03 13:43