O rany, to powodowało u mnie ból głowy przez kilka dni i nie mogłem wymyślić, jak to zrobić. Najgorsze było to, że stworzenie nowego projektu Xcode na iOS z szablonem master-detail działało dobrze. Na szczęście ostatecznie ten mały fakt polegał na tym, jak znalazłem rozwiązanie.
Znalazłem kilka postów sugerujących, że rozwiązaniem jest zaimplementowanie nowej primaryViewControllerForCollapsingSplitViewController:
metody na UISplitViewControllerDelegate
. Próbowałem tego bezskutecznie. To, co Apple robi w szablonie master-detail, który wydaje się działać, to zaimplementowanie nowej (weź głęboki oddech, aby powiedzieć wszystko to) splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:
metoda delegowania (ponownie włączona UISplitViewControllerDelegate
). Według dokumentacji ta metoda:
Prosi delegata o dostosowanie podstawowego kontrolera widoku i włączenie dodatkowego kontrolera widoku do zwiniętego interfejsu.
Koniecznie przeczytaj część dyskusyjną tej metody, aby uzyskać bardziej szczegółowe informacje.
Sposób, w jaki Apple radzi sobie z tym:
- (BOOL)splitViewController:(UISplitViewController *)splitViewController
collapseSecondaryViewController:(UIViewController *)secondaryViewController
ontoPrimaryViewController:(UIViewController *)primaryViewController {
if ([secondaryViewController isKindOfClass:[UINavigationController class]]
&& [[(UINavigationController *)secondaryViewController topViewController] isKindOfClass:[DetailViewController class]]
&& ([(DetailViewController *)[(UINavigationController *)secondaryViewController topViewController] detailItem] == nil)) {
// Return YES to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded.
return YES;
} else {
return NO;
}
}
Ta implementacja zasadniczo wykonuje następujące czynności:
- Jeśli
secondaryViewController
jest to, czego oczekujemy (a UINavigationController
) i pokazuje to, czego oczekujemy (a DetailViewController
- kontroler widoku), ale nie ma modelu ( detailItem
), to „ Return YES to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded.
”
- W przeciwnym razie wróć „,
NO
aby umożliwić kontrolerowi podzielonego widoku próbę włączenia zawartości dodatkowego kontrolera widoku do zwiniętego interfejsu”
Wyniki są następujące dla iPhone'a w orientacji pionowej (zaczynając w orientacji pionowej lub obracając się do portretu - lub dokładniej w klasie kompaktowej):
- Jeśli twój pogląd jest poprawny
- i ma model, pokaż kontroler widoku szczegółowego
- ale nie ma modelu, pokaż główny kontroler widoku
- Jeśli twój pogląd nie jest poprawny
- pokaż główny kontroler widoku
Czyste jak błoto.
UISplitViewController
i zawsze wracałemYES
z tej metody, a potem po prostu zmieniłem klasę podzielonego widoku w Storyboard, ponieważ zawsze chcę pokazać wzorzec na iPhonie w pionie. :)UISplitViewController
ale okazało się, że to nie zadziałało:splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:
nigdy nie został wezwany. Zamiast tego skopiowałem szablon Apple i umieściłem go w AppDelagate. To wymagało kilku zmian w tworzeniu UISplitViewController również podapplication didFinishLaunchingWithOptions:
(gdzie również skopiowałem szablon Apple).splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:
nigdy nie zostałem wezwany. Wygląda na to, że delegat jest poprawnie ustawianyapplicationDidFinishLaunchingWithOptions:
metoda delegata aplikacji . Czy ktoś inny widział ten problem i NIE miał tego rozwiązania?Oto akceptowana odpowiedź w języku Swift. Po prostu utwórz tę podklasę i przypisz ją do swojego splitViewController w swoim storyboardzie.
źródło
func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool {
Szybka wersja poprawnej odpowiedzi Marka S.
Zgodnie z szablonem Master-Detail firmy Apple.
Wyjaśnienie
(To, co powiedział Mark S, było nieco zagmatwane)
Ta metoda delegata jest wywoływana
splitViewController: collapseSecondaryViewController: ontoPrimaryViewController:
, ponieważ to właśnie robi. W przypadku zmiany na mniejszy rozmiar szerokości (na przykład podczas obracania telefonu z orientacji poziomej do pionowej), należy zwinąć kontroler widoku podzielonego na tylko jeden z nich.Ta funkcja zwraca wartość logiczną, aby zdecydować, czy powinna zwinąć szczegół i pokazać wzorzec, czy nie.
W naszym przypadku zdecydujemy się na podstawie tego, czy wybrano jakiś szczegół, czy nie. Skąd wiemy, czy wybrany został nasz szczegół? Jeśli postępujemy zgodnie z szablonem Master-Detail firmy Apple, kontroler widoku szczegółów powinien mieć opcjonalną zmienną zawierającą szczegółowe informacje, więc jeśli jest to zero (.None), nic nie zostało jeszcze wybrane i powinniśmy pokazać Master, aby użytkownik mógł coś wybrać.
Otóż to.
źródło
Apple's Master-Detail template
, nie ma być świetny ani zwięzły, tylko oparty na faktach. :)Z dokumentacji musisz użyć delegata, aby powiedzieć, że
UISplitViewController
ma nie włączać widoku szczegółowego do „zwiniętego interfejsu” (tj. „Trybu portretowego” w twoim przypadku). W języku Swift 4 nazwa metody delegata do zaimplementowania została zmieniona:źródło
.m:
źródło
Moja aplikacja została napisana w języku Swift 2.x i mogła działać dobrze. Po przekonwertowaniu go do Swift 3.0 (przy użyciu konwertera XCode), zaczyna wyświetlać najpierw szczegóły zamiast wzorca w trybie portretowym. Problem polega na tym, że nazwa funkcji splitViewController nie jest zmieniana, aby pasowała do nowej z UISplitViewControllerDelegate.
Po ręcznej zmianie nazwy tej funkcji moja aplikacja może teraz działać poprawnie:
źródło
self.delegate = self
naviewDidLoad
metodzie.Jeśli nie masz wartości domyślnych do pokazania w kontrolerze widoku szczegółowego, możesz po prostu usunąć domyślny przepływ między SplitViewController i szczegółowym UIViewController na tablicy scenariuszy. Dzięki temu zawsze najpierw trafi do Master View Controller.
Efektem ubocznym tego jest to, że zamiast widzieć dwa widoki w poziomie, zobaczysz jeden widok w pełnym rozmiarze w SplitViewController do momentu uruchomienia kontrolera Pokaż szczegóły płynne w kontrolerze widoku głównego.
źródło
Dla wszystkich, którzy nie mogli znaleźć piątkowej sekcji cs193p:
W Swift 3.1.1 utworzenie podklasy UISplitViewController i zaimplementowanie jednej z jej delegowanych metod działało dla mnie jak urok:
Mój scenorys
źródło
public func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool
Moim zdaniem powinieneś rozwiązać ten problem bardziej ogólny. Możesz podklasować UISplitViewController i zaimplementować protokół w osadzonych kontrolerach widoku.
Przykładowa implementacja w UITableViewController:
Mam nadzieję, że to pomoże. Możesz więc ponownie użyć tej klasy i po prostu zaimplementować protokół.
źródło
Po prostu usuń DetailViewController z kontrolerów SplitView, gdy potrzebujesz go do uruchomienia z poziomu głównego.
źródło
To zadziałało dla mnie na iOS-11 i Swift 4:
źródło
Nazwa funkcji została zmieniona w nowych wersjach Swift, więc ten kod działa w Swift 4:
źródło
Rozwiązanie Xamarin / C #
źródło
Po prostu ustaw
preferredDisplayMode
właściwośćUISplitViewController
to.allVisible
źródło