Mam jeden problem i opisałem go poniżej.
Używam UIViewControllerContextTransitioning
do niestandardowych przejść.
Mam 2 kontrolery widoku, pierwszy kontroler widoku i drugi kontroler widoku.
Teraz chcę dodać drugi kontroler widoku na pierwszym kontrolerze widoku z animacją. Udało mi się to, teraz drugi kontroler widoku jest przezroczysty, więc możemy zobaczyć pierwszy kontroler widoku poniżej drugiego kontrolera widoku.
Ale nie mogę zobaczyć pierwszego kontrolera widoku, a widzę tylko czarny ekran poniżej drugiego kontrolera widoku.
-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext{
self.transitionContext = transitionContext;
if(self.isPresenting){
[self executePresentationAnimation:transitionContext];
}
else{
[self executeDismissalAnimation:transitionContext];
}
}
-(void)executePresentationAnimation:(id<UIViewControllerContextTransitioning>)transitionContext{
UIView* inView = [transitionContext containerView];
UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
CGRect offScreenFrame = inView.frame;
offScreenFrame.origin.y = inView.frame.size.height;
toViewController.view.frame = offScreenFrame;
toViewController.view.backgroundColor = [UIColor clearColor];
fromViewController.view.backgroundColor = [UIColor clearColor];
inView.backgroundColor = [UIColor clearColor];
[inView insertSubview:toViewController.view aboveSubview:fromViewController.view];
// [inView addSubview:toViewController.view];
CFTimeInterval duration = self.presentationDuration;
CFTimeInterval halfDuration = duration/2;
CATransform3D t1 = [self firstTransform];
CATransform3D t2 = [self secondTransformWithView:fromViewController.view];
[UIView animateKeyframesWithDuration:halfDuration delay:0.0 options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^{
[UIView addKeyframeWithRelativeStartTime:0.0f relativeDuration:0.5f animations:^{
fromViewController.view.layer.transform = t1;
}];
[UIView addKeyframeWithRelativeStartTime:0.5f relativeDuration:0.5f animations:^{
fromViewController.view.layer.transform = t2;
}];
} completion:^(BOOL finished) {
}];
[UIView animateWithDuration:duration delay:(halfDuration - (0.3*halfDuration)) usingSpringWithDamping:0.7f initialSpringVelocity:6.0f options:UIViewAnimationOptionCurveEaseIn animations:^{
toViewController.view.frame = inView.frame;
} completion:^(BOOL finished) {
[self.transitionContext completeTransition:YES];
}];
}
Po [self.transitionContext completeTransition:YES];
wywołaniu nagle pierwszy kontroler widoku znika, a pod drugim kontrolerem widoku pojawia się czarny ekran.
Czy ktoś ma pomysł? Dzięki.
źródło
modalPresentationStyle = UIModalPresentationFullScreen
. Oczywiście nadal otrzymujesz niestandardową animację przejścia.Uważam, że należy lepiej wyjaśnić uzasadnienie tego.
Widok znika, ponieważ usuwasz widok kontrolera widoku prezentacji z jego pierwotnej lokalizacji (hierarchia widoków), umieszczasz go w module containerView, który zapewnia Twój animator, ale nigdy nie zwraca go z powrotem po zakończeniu animacji. Tak więc widok kontrolera widoku jest całkowicie usuwany wraz z jego superviewem (containerView) z okna.
W iOS 7 system zawsze przywracał widoki kontrolerów widoku, które są zaangażowane w prezentację (prezentację i prezentację), do ich oryginalnych miejsc po automatycznym zakończeniu animacji przejścia. Tak się już nie dzieje w przypadku niektórych stylów prezentacji w iOS 8.
Zasada jest bardzo prosta: animator powinien manipulować widokiem kontrolera widoku prezentacji tylko wtedy, gdy widok kontrolera widoku ma zostać całkowicie ukryty (usunięty z hierarchii widoków) do końca przejścia . Innymi słowy, oznacza to, że po zakończeniu animacji początkowej prezentacji będzie widoczny tylko widok kontrolera prezentowanego widoku, a nie widok kontrolera widoku prezentacji. Na przykład, jeśli ustawisz nieprzezroczystość widoku kontrolera widoku prezentowanego na 50% i użyjesz UIModalPresentationFullScreen, nie będziesz mógł zobaczyć widoku kontrolera widoku prezentującego pod prezentowanym, ale jeśli użyjesz UIModalPresentationOverFullscreen - tak (
shouldRemovePresentersView
za określenie tego odpowiada metoda UIPresentationController ).Dlaczego nie pozwolić animatorowi na ciągłe manipulowanie widokiem kontrolera widoku prezentacji? Po pierwsze, jeśli widok kontrolera widoku prezentacji ma pozostać widoczny po zakończeniu animacji przez cały cykl życia prezentacji, nie ma potrzeby jej w ogóle animować - po prostu pozostaje tam, gdzie jest. Po drugie, jeśli własność tego kontrolera widoku zostanie przeniesiona na kontroler prezentacji, najprawdopodobniej kontroler prezentacji nie będzie wiedział, jak rozmieścić widok tego kontrolera widoku w razie potrzeby, na przykład w przypadku zmiany orientacji, ale pierwotny właściciel kontrolera widoku prezentacji tak .
W iOS 8
viewForKey:
wprowadzono metodę uzyskiwania widoków, którymi manipuluje animator. Po pierwsze, pomaga postępować zgodnie z zasadą opisaną powyżej, zwracając zero, gdy animator nie powinien dotykać widoku. Po drugie, animator może zwrócić inny widok do animacji. Wyobraź sobie, że wdrażasz prezentację podobną do arkusza formularzy. W tym przypadku chciałbyś dodać cień lub dekorację wokół widoku kontrolera prezentowanego widoku. Zamiast tego animator ożywi tę dekorację, a widok kontrolera widoku prezentowanego będzie dzieckiem tej dekoracji.viewControllerForKey:
nie znika, można go nadal używać, jeśli potrzebny jest bezpośredni dostęp do kontrolerów widoku, ale animator nie powinien robić żadnych założeń dotyczących widoków, które ma animować.Jest kilka rzeczy, które możesz zrobić, aby poprawnie rozwiązać problem ze znikającym widokiem kontrolera widoku prezentacji, gdy umieścisz go bezpośrednio w widoku kontenera animatora:
Jeśli nie ma potrzeby animowania widoku kontrolera widoku prezentacji, użyj
viewForKey:
polecenia, aby animować widoki, zamiast sięgać do widoków kontrolera bezpośrednio.viewForKey:
może zwrócić zerowe lub nawet zupełnie inne poglądy.Jeśli chcesz animować widok kontrolerów widoku prezentacji, powinieneś rozważyć użycie
UIModalPresentationFullScreen
style lub kontynuować używanieUIModalPresentationCustom
i zaimplementować własną podklasę UIPresentationController zshouldRemovePresentersView
zwracaniemYES
. W rzeczywistości implementacja tej metody jest główną różnicą między wewnętrznymi kontrolerami prezentacji zdefiniowanymi przezUIModalPresentationFullScreen
iUIModalPresentationCustom
stylami, poza tym, że ten ostatni pozwala na użycie niestandardowych kontrolerów prezentacji.We wszystkich innych rzadkich przypadkach będziesz musiał przywrócić widok kontrolera widoku prezentacji do jego pierwotnej lokalizacji, zgodnie z sugestiami innych odpowiedzi.
źródło
viewControllerForKey:
„sview
s tylko kiedyviewForKey:
powraca zerowa, a ja nadal musiał ponownie dodać ją do okna ręcznie. Czy masz przykład kodu działającego bez tego obejścia?viewForKey:
zwraca zero, na pewno będziesz musiał ponownie dodać widok kontrolera widoku prezentacji do okna, jeśli usuniesz go z niego w swoim animatorze. W przypadku, gdy viewForKey zwraca widok rzeczywistego kontrolera widoku, można bezpiecznie przenieść ten widok, ponieważ UIKit przeniósłby go z powrotem do pierwotnej pozycji po zakończeniu cyklu życia prezentacji.W systemie iOS 8 należy manipulować widokami zwracanymi przez
viewForKey:
zamiast.view
właściwości kontrolerów widoku zwróconych przezviewControllerForKey:
. Nie jest to szczególnie jasne w dokumentacji beta, ale jeśli spojrzysz na źródło UIViewControllerTransitioning.h, zobaczysz ten komentarz powyżejviewControllerForKey:
:Dlatego zamiast dostosowywania ramek itp.
toViewController.view
Użyj wartości zwracanej przez[transitionContext viewForKey:UITransitionContextToViewKey]
.Jeśli Twoja aplikacja musi obsługiwać iOS7 i / lub Xcode 5, możesz użyć prostej metody kategorii na UIViewController, jak poniżej:
Następnie zdobądź swoje
toViewController
ifromViewController
jak zwykle, ale uzyskaj widoki za pomocą[toViewController viewForTransitionContext:transitionContext]
.Edycja: Wygląda na to, że jest błąd
viewForKey
polegający na tym, że widok kontrolera widoku prezentacji jest zerowy po powrocie z , co uniemożliwia wykonanie przejść modalnych, które w ogóle animują widok prezentacji (takich jak zsuwanie się lub obracanie w poziomie). Zgłosiłem błąd dla iOS8 na rdar: // 17961976 ( http://openradar.appspot.com/radar?id=5210815787433984 ). Zobacz także przykładowy projekt pod adresem http://github.com/bcherry/TransitionBugEdycja 2: Dzięki graveley za sugestię, użycie UIModalPresentationFullScreen rozwiązuje problem. Być może to nie jest błąd. Apple może chcieć, aby UIModalPresentationCustom modyfikował tylko widok przychodzącego modalu. Jeśli chcesz zmodyfikować widok wychodzący, musisz zagwarantować prezentację nowego widoku na pełnym ekranie? W każdym przypadku należy użyć
viewForKey
i UIModalPresentationFullScreen.źródło
manipulating
poglądy VC, czy nie ...viewForKey
błąd w GM. Czy inni też? Czy znalazłeś rozsądne obejście tego problemu?- viewForKey
// viewForKey: może zwrócić nil, co oznaczałoby, że animator nie powinien manipulować widokiem powiązanego kontrolera widoku. Powrótnil
nie jest błędem.viewForKey
zwraca z widoku i do widoku. Może więc celowo zwraca zero dla UIModalPresentationCustom. Aktualizuję raport o błędzie i wrócę tutaj, jeśli otrzymam informację od Apple.Brak ustawienia
modalPresentationStyle
na UIModalPresentationCustom rozwiązał problem.Innymi słowy, pozostawienie wartości domyślnej UIModalPresentationFullScreen zamiast określania UIModalPresentationCustom rozwiązało problem znikającego widoku. Zwróć uwagę, że protokół UIViewControllerTransitioningDelegate nadal wydaje się być przestrzegany, nawet jeśli pozostawiasz to ustawienie domyślne. Jeśli dobrze pamiętam, kiedyś UIModalPresentationCustom był wymagany.
Działa do tej pory, próbowałem tego tylko w przypadku nieinteraktywnych animacji.
źródło
viewForKey:
zamiast.view
naviewControllerForKey:
rozwiązaniu wszystkich problemów dla mnie.Znalazłem tę niezwykle przydatną odpowiedź w powiązanym wątku autorstwa Lefterisa: https://stackoverflow.com/a/27165723/3709173
Podsumowując:
+1 w niestandardowym przejściu, nie dodawaj do View, gdy ma miejsce animacja zwolnienia.
Zademonstrowano tutaj:
https://www.dropbox.com/s/7rpkyamv9k9j18v/CustomModalTransition.zip?dl=0 bez żadnych hacków! to jest jak magia! :)
źródło
W systemie iOS 8 musisz utworzyć UIPresentationController i zaimplementować poniższą metodę w UIViewControllerTransitioningDelegate.
Aby uzyskać więcej informacji, obejrzyj wideo WWDC 2014:
https://developer.apple.com/videos/wwdc/2014/?include=228
Istnieje również przykładowy kod z WWDC o nazwie „LookInside: Presentation Controllers Adaptivity and Custom Animator Objects”, który można pobrać z przykładowej strony kodowej WWDC 2014.
Być może trzeba będzie trochę zmienić przykładowy kod. Metoda init UIPresentationController została zmieniona na:
Wcześniej prezentował, a potem prezentował. Po prostu zamień je i powinno działać.
źródło
zamiast [inView insertSubview: toViewController.view aboveSubview: fromViewController.view]; po prostu dodaj: [inView addSubview: toViewController.view];
Możesz zobaczyć przykład tutaj: link i działa na iOS 7 i iOS 8
źródło
Oto wersja poprawki Asha w Objective C.
Musiałem zamienić kolejność i wywołać metodę [przejścieContext completeTransition:] po ponownym dodaniu widoku, aby wyświetlić nowy kontroler widoku z bloku zakończenia zwolnienia innego kontrolera widoku, aby działał poprawnie.
Nie wiem, czy to rozwiąże problem dla wszystkich, ale działa w mojej aplikacji. Twoje zdrowie!
źródło
Okazało się, że to działa dobrze dla Obj-C:
Wydaje się, że działa dobrze na ios7 i ios8.
źródło
Odkryłem, że
viewForKey:UITransitionContextToViewKey
zwraca zero na ios8. Więc jeśli jest zerowy, pobieram widok z kontrolera widoku „do”.Jednak wydaje się, że powoduje to, że widok „do” nie jest przenoszony z kontenera do okna po
completeTransition:YES
wywołaniu. Więc jeśliviewForKey:UITransitionContextToViewKey
zwraca zero, przewracam się dotoVC.view
i śledzę fakt, że zwróciło zero, a po zakończeniu przenoszę go do początkowego nadzoru kontenera (który jest oknem).Tak więc ten kod działa zarówno na iOS7, jak i iOS8 i powinien działać również na iOS9, nawet jeśli to naprawią, czy nie.
źródło
Odkryłem, że ten błąd (i wiele więcej!) Znika, jeśli ustawisz
modalPresentationStyle = UIModalPresentationFullScreen
. Oczywiście nadal otrzymujesz niestandardową animację przejścia.źródło
W tej kwestii też utknąłem. Chciałem stworzyć niestandardowe przejście z półprzezroczystym tłem, w którym nadal mogłem zobaczyć kontroler widoku, z którego pochodzę, ale mam tylko czarne tło. Znalazłem odpowiedź Marka Arona w tym wątku, która pomogła mi, ale jest napisana w celu C, więc oto wersja Swift 3 tej odpowiedzi, którą przetestowałem dla iOS 9 i iOS 10:
Utwórz podklasę UIPresentationController. Zastąp shouldRemovePresentersView na false w następujący sposób:
W miejscu, w którym tworzysz wystąpienie nowego kontrolera widoku i ustawiasz jego delegata przejścia, wskaż, że chcesz, aby pokazywał niestandardowy styl prezentacji modalnej w następujący sposób:
Teraz Zastąp metodę PresentationController UIViewControllerTransitioningDelegate i zwróć niestandardowy UIPresentationController. Miałem swój jako rozszerzenie mojej obecnej klasy:
Inną rzeczą wartą uwagi jest to, że nie powinieneś próbować odwoływać się do fromView w swojej klasie presentAnimator. To będzie zero i pojawi się błąd w czasie wykonywania. Poza tym, jeśli zaimplementujesz takie rzeczy, otrzymasz niestandardowe przejście z animacją i półprzezroczystym tłem, jeśli je utworzysz.
źródło
presentationController(forPresented presented UIViewController,...
ponieważ poprzedni interfejs API Swift nie zakłócił zgodności, ale nie został wywołany.Po napotkaniu tego problemu byłem bardzo zdezorientowany, ponieważ niedawno napisałem coś prawie identycznego, co działało dobrze. Przyszedłem tutaj, szukając odpowiedzi, aby znaleźć poprawki, które wyglądają dość hakersko i wydają się nie rozumieć głównej przyczyny ... w rzeczywistości jest to bardzo łatwe do naprawienia.
Niektóre odpowiedzi wspominają o zmianie
modalPresentationStyle
na.overFullScreen
. To prawda, też.overCurrentContext
by działało. Jest to oczekiwane, a zachowanie dokumentów Apple. Ale dlaczego to nie działa dla wszystkich? Po co ten cały hackerski kod i kombinacje tego z czymś innym i szalonymi rzeczami, których nie powinieneś robić?Okazuje się, że musisz ustawić styl prezentacji ZANIM WIDOK ZAŁADUJE . Nie później. Zrób to w init, zrób to z poprzedniego kontrolera, lub jak chcesz - o ile jest to przed załadowaniem widoku.
źródło
.overCurrentContext
init
Użycie nowego UIModalPresentationOverCurrentContext naprawiło to za mnie. Moje pierwotne przejście na iOS 7 polegało tylko na rozmytym tle widoku pod modalem.
źródło
Ok, myślę, że rozwiązuję jeden przypadek, w którym „działający animator” przestaje działać poprawnie, gdy tworzysz aplikację w iOS 13 i nowszych.
Env Xcode 11.1, iOS 13.1
Problem
To, co chcę zrobić, jest bardzo proste: mam widok kolekcji, po dotknięciu komórki przechodzi do widoku szczegółowego. Zamiast używać nudnego domyślnego stylu „prezentuj modalnie”, chcę uczynić go bardziej interesującym, więc napisałem animator do przejścia kontrolera widoku.
Skonfigurowałem segue w IB, przeciągając i upuszczając z mojej kolekcji VC do VC szczegółów. Styl przejścia to „Obecny modalnie”, a prezentacja jest ustawiona na „Pełny ekran”.
Kiedy pokazuje widok szczegółowy, wszystko działa zgodnie z oczekiwaniami. Jednak kiedy zamykam widok szczegółów i wracam do widoku kolekcji, widzę tylko animowany widok szczegółów, widok kolekcji po prostu zniknął. Grzebałem tu i tam i mam kilka odkryć
1. tuż po wywołaniu następującego wiersza z funkcji `` animateTransition () '' widok kolekcji zostaje wznowiony i pojawia się
2. Tak długo, jak widok szczegółowy nie obejmuje w pełni widoku kolekcji, widok kolekcji nie zniknie po przejściu z widoku szczegółowego
Rozwiązanie
Szczerze mówiąc, niewiele wiem o tym, jak działa animowane przejście. Więc mogę tylko śledzić ten post i drugi , wypróbuj każdą z odpowiedzi. Niestety żaden z nich nie działa dla mnie. W końcu doszedłem do punktu, w którym jedyne, co mogę zmienić, to styl prezentacji segue w IB (co powinienem był zrobić na samym początku). Kiedy ustawię prezentację na „Pełny ekran”, dzieje się cud i mój problem zostaje rozwiązany. Widok szczegółów może być wyświetlany na pełnym ekranie z animacją, a kiedy zostanie zamknięty, widzę zarówno widok kolekcji jako tło, jak i animowany widok szczegółów.
Potem jeszcze jedno odkrycie na drodze
Aby odwołać się do „toView” i „fromView”, działają obie poniższe metody
Pośrednio:
Bezpośrednio sposób:
Ale kiedy zmieniłem styl płynności na „Over Full Screen”, bezpośredni sposób zwracania „nil” zarówno dla „toView”, jak i „fromView” i tylko pośrednio działa, ten problem jest również wspomniany w innym poście , więc myślę, że warto opublikować tutaj moje małe odkrycie.
Mam nadzieję, że w przyszłości będzie to pomocne dla kogoś.
źródło
Miałem ten sam problem podczas zamykania kontrolera widoku treści.
Moja aplikacja ma ten nadrzędny kontroler widoku, który pokazuje modalnie podrzędny kontroler widoku (prezentujący vc). Następnie, gdy zostanie dotknięty widok podrzędny w childVC, pokazuje inny vc (który nazywam kontrolerem widoku zawartości (przedstawiony vc))
Mój problem polega na tym, że po odrzuceniu contentVC (teraz prezentujący VC), powinien on przejść do podrzędnego VC (teraz przedstawiony VC), ale gdy tylko zakończy się moje niestandardowe przejście, childVC nagle znika, pokazując nadrzędny VC.
To, co zrobiłem, aby rozwiązać ten problem, to
.modalPresentationStyle
childVC prezentowane przez parentVC z domyślnego.automatic
na.fullscreen
..modalPresentationStyle
contentVC na.fullscreen
.To rozwiązuje problem. ale nie pokaże twojego dziecka VC jako arkusza w stylu karty na górze parentVC (podczas używania
.overCurrentContext
lub automatycznego), co jest nowe w iOS 13.Chciałbym wiedzieć, czy istnieje rozwiązanie, które zachowa arkusz stylu karty dla childVC, gdy zostanie przedstawiony przez rodzica.
źródło
dodaje kontroler widoku jako element podrzędny innego kontrolera widoku.
sprawdź i daj mi znać.
źródło