Muszę wykonać pewne czynności, gdy przycisk Wstecz (powrót do poprzedniego ekranu, powrót do widoku rodzica) jest naciśnięty na pasku nawigacyjnym.
Czy jest jakaś metoda, którą mogę zaimplementować, aby złapać zdarzenie i uruchomić pewne akcje, aby wstrzymać i zapisać dane, zanim ekran zniknie?
iphone
objective-c
ios
xcode
ewok
źródło
źródło
Odpowiedzi:
AKTUALIZACJA: Według niektórych komentarzy, rozwiązanie w oryginalnej odpowiedzi nie wydaje się działać w niektórych scenariuszach w iOS 8+. Nie mogę zweryfikować, że tak jest bez dalszych szczegółów.
Dla tych z Was jednak w takiej sytuacji jest alternatywa. Wykrywanie, kiedy kontroler widoku jest otwierany, jest możliwe poprzez nadpisanie
willMove(toParentViewController:)
. Podstawową ideą jest to, że kontroler widoku jest otwierany, gdyparent
jestnil
.Więcej informacji można znaleźć w sekcji „Implementowanie kontrolera widoku kontenera” .
Od czasu iOS 5 stwierdziłem, że najłatwiejszym sposobem radzenia sobie z tą sytuacją jest użycie nowej metody
- (BOOL)isMovingFromParentViewController
:- (BOOL)isMovingFromParentViewController
ma sens, gdy pchasz i umieszczasz kontrolery w stosie nawigacyjnym.Jeśli jednak prezentujesz kontrolery widoku modalnego, powinieneś
- (BOOL)isBeingDismissed
zamiast tego użyć :Jak wspomniano w tym pytaniu , możesz połączyć obie właściwości:
Inne rozwiązania opierają się na istnieniu pliku
UINavigationBar
. Zamiast tego bardziej podoba mi się moje podejście, ponieważ oddziela wymagane zadania do wykonania od akcji, która wywołała zdarzenie, tj. Naciśnięcie przycisku Wstecz.źródło
self.isMovingFromParentViewController
ma wartość TRUE, gdy programowo wyświetlam stos nawigacjipopToRootViewControllerAnimated
- bez dotykania przycisku Wstecz. Czy powinienem zlekceważyć twoją odpowiedź? (temat mówi, że na pasku nawigacyjnym naciśnięto przycisk „wstecz”)override func viewWillDisappear(animated: Bool) { super.viewWillDisappear(animated) if isMovingFromParentViewController(){ println("back button pressed") } }
-viewDidDisappear:
ponieważ możliwe jest, że otrzymasz-viewWillDisappear:
bez znaku-viewDidDisappear:
(np. Kiedy zaczniesz przesuwać, aby odrzucić element kontrolera nawigacji, a następnie anulujesz to przesunięcie.Podczas gdy
viewWillAppear()
iviewDidDisappear()
są wywoływane po dotknięciu przycisku Wstecz, są również wywoływane w innych przypadkach. Zobacz koniec odpowiedzi, aby uzyskać więcej informacji na ten temat.Korzystanie z UIViewController.parent
Wykrywanie przycisku wstecz jest lepsze, gdy VC jest usuwany z jego elementu nadrzędnego (NavigationController) za pomocą
willMoveToParentViewController(_:)
LUBdidMoveToParentViewController()
Jeśli rodzic ma wartość zero, kontroler widoku jest zdejmowany ze stosu nawigacji i odrzucany. Jeśli rodzic nie jest nil, jest dodawany do stosu i prezentowany.
Zamień się
willMove
nadidMove
i check self.parent do pracy po kontroler widoku zostaje odrzucona.Zatrzymanie zwolnienia
Zwróć uwagę, że sprawdzenie rodzica nie pozwala na „wstrzymanie” przejścia, jeśli musisz wykonać jakiś rodzaj asynchronicznego zapisu. Aby to zrobić, możesz zaimplementować następujące. Jedynym minusem jest to, że tracisz fantazyjny / animowany przycisk Wstecz w stylu iOS. Uważaj również tutaj na interaktywny gest machnięcia. Użyj poniższych, aby obsłużyć ten przypadek.
Więcej na widoku pojawi się / pojawiło się
Jeśli nie masz
viewWillAppear
viewDidDisappear
problemu, przeanalizujmy przykład. Załóżmy, że masz trzy kontrolery widoku:Pozwala śledzić połączenia w
detailVC
miarę przechodzenia odlistVC
dosettingsVC
iz powrotemlistVC
Lista> Szczegóły (push szczegółyVC)
Detail.viewDidAppear
<- wyświetlSzczegóły> Ustawienia (ustawienia pushVC )
Detail.viewDidDisappear
<- znikająA jak wrócimy ...
Ustawienia> Szczegóły (wyskakują ustawieniaVC)
Detail.viewDidAppear
<- pojawiają sięszczegóły> Lista (pojawiają się szczegółyVC)
Detail.viewDidDisappear
<- znikająZauważ, że
viewDidDisappear
jest to wywoływane wiele razy, nie tylko podczas cofania, ale także podczas jazdy do przodu. Dla szybkiej operacji, która może być pożądana, ale dla bardziej złożonej operacji, takiej jak połączenie sieciowe w celu zapisania, może nie być.źródło
didMoveToParantViewController:
ma wykonać pracę, gdy widok nie jest już widoczny. Pomocne dla iOS7 dzięki interaktywnemu_ = self.navigationController?.popViewController(animated: true)
go programowo , więc nie jest wywoływane tylko po naciśnięciu przycisku Wstecz. Szukam połączenia, które działa tylko po naciśnięciu przycisku Wstecz.Pierwsza metoda
Druga metoda
źródło
Mylą się ci, którzy twierdzą, że to nie działa:
To działa dobrze. Więc co jest przyczyną rozpowszechnienia się mitu, że tak nie jest?
Problem wydaje się wynikać z nieprawidłowej implementacji innej metody, a mianowicie z tego, że implementacja
willMove(toParent:)
zapomniała zadzwonićsuper
.Jeśli zaimplementujesz
willMove(toParent:)
bez wywołaniasuper
, toself.isMovingFromParent
będziefalse
i użycieviewWillDisappear
będzie wyglądało na niepowodzenie. Nie zawiodło; zepsułeś to.UWAGA: Prawdziwym problemem jest zwykle to, że drugi kontroler widoku wykrył, że pierwszy kontroler widoku został włamany. Zobacz także bardziej ogólną dyskusję tutaj: Unified UIViewController "stał się pierwszym" wykrywaniem?
EDYCJA Komentarz sugeruje, że powinno to być
viewDidDisappear
raczej niżviewWillDisappear
.źródło
true
dla interaktywnego gestu machnięcia pop - z lewej krawędzi kontrolera widoku - nawet jeśli przesunięcie nie spowodowało całkowitego wyskoczenia. Więc zamiast sprawdzać towillDisappear
wdidDisappear
pracy.Gram (lub walczę) z tym problemem przez dwa dni. IMO najlepszym podejściem jest po prostu utworzenie klasy rozszerzenia i protokołu, na przykład:
To działa, ponieważ
UINavigationController
otrzyma wywołanie zanavigationBar:shouldPopItem:
każdym razem, gdy zostanie wyświetlony kontroler widoku. Tam wykrywamy, czy przycisk Back został naciśnięty, czy nie (inny przycisk). Jedyne, co musisz zrobić, to zaimplementować protokół w kontrolerze widoku, w którym naciśnięto przycisk wstecz.Pamiętaj, aby ręcznie włożyć kontroler widoku do środka
backButtonPressedSel
, jeśli wszystko jest w porządku.Jeśli masz już podklasę
UINavigationViewController
i zaimplementowałeś jąnavigationBar:shouldPopItem:
, nie martw się, to nie będzie ci przeszkadzać.Możesz być także zainteresowany wyłączeniem gestu cofania.
źródło
Działa to dla mnie w iOS 9.3.x z Swift:
W przeciwieństwie do innych rozwiązań tutaj, nie wydaje się to wywoływać nieoczekiwanie.
źródło
Dla przypomnienia, myślę, że tego szukał bardziej…
źródło
Jak
purrrminator
mówi, odpowiedź przezelitalon
nie jest całkowicie poprawna, ponieważyour stuff
zostanie wykonana nawet podczas programowego wyskakiwania kontrolera.Rozwiązanie, które znalazłem do tej pory nie jest zbyt ładne, ale na mnie działa. Poza tym, co
elitalon
powiedziałem, sprawdzam też, czy wyskakuję programowo, czy nie:Musisz dodać tę właściwość do swojego kontrolera i ustawić ją na TAK przed programowym pojawieniem się:
Dzięki za pomoc!
źródło
Najlepszym sposobem jest użycie metod delegata UINavigationController
Dzięki temu można dowiedzieć się, jaki kontroler wyświetla UINavigationController.
źródło
Rozwiązałem ten problem, dodając UIControl do paska nawigacji po lewej stronie.
I musisz pamiętać, aby go usunąć, gdy zniknie widok:
To wszystko!
źródło
Możesz skorzystać z wywołania zwrotnego przycisku Wstecz, na przykład:
dla szybkiej wersji możesz zrobić coś podobnego w zakresie globalnym
Poniżej umieszczasz kontroler widoku, w którym chcesz sterować działaniem przycisku Wstecz:
źródło
navigationShouldPopOnBackButton
bierze? Nie jest częścią publicznego interfejsu API.Jak powiedział Coli88, powinieneś sprawdzić protokół UINavigationBarDelegate.
Mówiąc bardziej ogólnie, możesz również użyć
- (void)viewWillDisapear:(BOOL)animated
do wykonania niestandardowej pracy, gdy widok zachowany przez aktualnie widoczny kontroler widoku wkrótce zniknie. Niestety, obejmowałoby to kłopotliwe przypadki push i pop.źródło
Dla Swift z kontrolerem UINavigationController:
źródło
Odpowiedź 7ynk3r była bardzo zbliżona do tego, czego użyłem na końcu, ale wymagała pewnych poprawek:
źródło
Powinieneś sprawdzić protokół UINavigationBarDelegate . W takim przypadku możesz użyć metody navigationBar: shouldPopItem:.
źródło
self.navigationController.isMovingFromParentViewController nie działa już na iOS8 i 9 używam:
źródło
(SZYBKI)
ostatecznie znalazłem rozwiązanie .. szukaną metodą jest "willShowViewController", która jest metodą delegowaną dla UINavigationController
źródło
MyViewController
z nimPushedController
.