2

Я реализую универсальное приложение, использующее UISplitViewController для iOS8 и столкнувшись с непонятной проблемой с UINavigation и очень ценю ваш опыт.UISplitViewController's detail view push error

Мой проект имеет следующий раскадровке расположение: UINavigation in UISplitViewController

На IPad, все работает, как ожидалось. Однако, работая на iPhone, навигация не работает должным образом. Пожалуйста, см. Этот short video, демонстрирующий проблему с навигацией, когда я перемещаюсь из «Подробного экрана 2» обратно к «Экран детали 1».

Я попытался реализовать этот же сценарий в совершенно новом проекте, но я не видел проблемы. Только после переноса в мой существующий проект я вижу это поведение.

UPDATE 1:

Вот мой AppDelegate код:

@interface AppDelegate() <UISplitViewControllerDelegate> 

    @end 

    @implementation AppDelegate 

    -(BOOL) application: (UIApplication*) application didFinishLaunchingWithOptions: (NSDictionary*) launchOptions { 

     UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController; 
     UINavigationController *navigationController = [splitViewController.viewControllers lastObject]; 
     navigationController.topViewController.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem; 
     splitViewController.delegate = self; 

     splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModeAllVisible; 

     return YES; 
    } 

    #pragma mark - Split view 

    - (BOOL)splitViewController:(UISplitViewController *)splitViewController collapseSecondaryViewController:(UIViewController *)secondaryViewController ontoPrimaryViewController:(UIViewController *)primaryViewController { 

     return YES; 
    } 

.... 
@end 

UPDATE 2:

Благодаря PetahChristian, я думаю, что его замечание ниже верно:

К co llapse контроллер вторичного представления, который имеет контроллер навигации , Apple вставляет дополнительный навигационный контроллер в стек основного контроллера навигационной системы . Итак, для iPhone, где вы видите проблемы, похоже, что есть только одна навигация , но на самом деле есть два.

Предполагая, что наблюдение является правильным, как можно предотвратить включение второго навигационного контроллера на главный навигационный контроллер? Методы UISplitViewControllerDelegate обрабатывают только процедуру коллапса для контроллера вторичного представления. Прямо связаны с UISplitViewController. В моем случае контроллер вторичного представления, который должен быть свернут (а именно Detail VC1), маршрутизируется через «« Показать детали (например, «Заменить») «segue из главного контроллера представления и методы UISplitViewControllerDelegate не выполняются во время этого перехода.

С такой же настройкой в ​​совершенно новом проекте Apple не вставляет дополнительный контроллер навигации в основной контроллер навигации, и я не испытываю этой проблемы в новом проекте.

Большое спасибо.

+0

Я прочитал ваш обновленный вопрос. Контроллер вторичного обзора действительно является контроллером вторичной навигации. Посмотрите на свою раскадровку. Вы можете видеть дополнительный контроллер навигации, а Detail VC1 - его дочерним элементом. Когда splitView сворачивается, вторичный контроллер навигации должен свернуть на основном. Apple действительно вставляет дополнительный контроллер навигации в контроллер основного вида. Вот почему они проверяют на '[secondaryViewController isKindOfClass: [UINavigationController class]] ...' См. Мой ответ для более подробной информации. –

+0

Спасибо ПетахЧристайн. Я абсолютно ценю вашу помощь по этой теме, вы помогли мне больше узнать о UISplitViewControllerDelegate. Я нашел виновника своей проблемы и разместил свой ответ ниже. Еще раз спасибо. –

ответ

2

Преступник, вызывающий эту навигационную особенность в моем проекте, был связан с расширением, которое я скачал от пользователя SO, вызванного UIViewController+BackButtonHandler. Этот обработчик перехватывает кнопку навигации, чтобы я мог получить дополнительную работу, когда пользователь нажимает. Этот код расширения категории переопределяет navigationBar:shouldPopItem:, что приводит к разрыву навигации по умолчанию. Я понятия не имел, что этот код выполняет, потому что я не использовал его, а просто включил в свой проект. Вау ... 2 дня ударился головой о стену.

+1

Я очень рад, что вы нашли проблему! Хорошее эмпирическое правило состоит в том, что, если мы должны «обойти» способ Apple делать вещи, у нас, скорее всего, отсутствует правильный способ справиться с этим. Если вы спросите, как сделать дополнительную работу, когда пользователь нажимает назад, вы можете найти лучший способ выполнить это, что не связано с перехватом нормального поведения :) –

+0

@Loc Pham вы спасли мой день –

1

Это ведет себя по-разному между проектами, потому что код UISplitViewControllerDelegate отличается.

Новый проект имеет необходимый код, но в существующем проекте может отсутствовать его.

Проверьте AppDelegate и сравните код, который рубит ручку и отделяет контроллер дополнительного вида.

-splitViewController:collapseSecondaryViewController:ontoPrimaryViewController: 
-splitViewController:separateSecondaryViewControllerFromPrimaryViewController: 

Update:

Вы не должны безоговорочно вернуть YES в splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:. Вы должны сначала определить, какой контроллер просмотра находится наверху. Посмотрите, как они проверяют, является ли это контроллером подробных представлений (дополнительный контроллер навигации и его дочерний элемент), и у него есть детали для отображения?

- (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; 
    } 
} 

Обновление 2:

Чтобы свернуть вторичный контроллер, который имеет вид навигации контроллер, Apple, вставляет вторичный контроллер навигации на стек основной контроллер навигационной в. Итак, для iPhone, где вы видите проблемы, похоже, что есть только один контроллер навигации, но на самом деле их два.

В вашем видео, когда он выглядит так, как будто вы находитесь у мастера, но у него есть кнопка «Назад», и вы нажимаете на него, а кнопка «Назад» сместится с экрана, это дополнительный навигационный контроллер, исчезающий с основного навигационного контроллера ,

Чтобы ваш проект работал правильно, вам придется условно протестировать контроллер навигации, например, яблоко, чтобы определить, отбрасывается ли контроллер (контроллер навигации и его дочерний элемент) или нет.

Обновление 3:

Навигационный контроллер, сам по себе, является контроллер представления. Он контролирует контроллеры просмотра детей.

Контроллер вторичной навигации является контроллер вторичного вида. Контроллер детального представления - это контроллер дочернего представления.

То, что обрабатывают методы делегата splitView, - это сбой или разделение вторичного контроллера навигации, который, случается, имеет один или несколько контроллеров детского вида.

Когда контроллер splitView свернут, стек основного навигационного контроллера выглядит как [masterViewController, secondaryNavigationController].

Что касается замены segue, то вы заменяете контроллер пустой детали в нижней части раскадровки, с оранжевым экраном детализации 1. Но замененный контроллер подробного представления по-прежнему имеет родительский контроллер вторичной навигации. И когда splitViewController рушится, вторичный контроллер навигации заканчивается в стеке основного навигационного контроллера. Вы этого не видите, потому что это прозрачно. Все, что вы видите, это экран детали 1, потому что это контроллер верхнего уровня вторичного навигационного контроллера.

Ваш код splitViewDelegate нарушен. Поэтому при нажатии кнопки «Назад» контролеры просмотра не ожидают надлежащего воспроизведения видео. Исправьте код делегата, и все будет выглядеть и работать правильно.

Вам определенно необходимы как крах, так и отдельные методы, и они должны поступать правильно. Вот почему я рекомендую вам использовать код Apple вместо того, чтобы пытаться написать свой собственный, потому что код Apple правильно рушится и отделяет навигационный контроллер.

+0

Мой метод UISplitViewControllerDelegate прост, он просто возвращает YES для splitViewController: collapseSecondaryViewController: onPrimaryViewController: и я не реализую -splitViewController: separateSecondaryViewControllerFromPrimaryViewController: –

+0

Опубликуйте свой код 'UISplitViewControllerDelegate'. В нем есть ошибка, поскольку существующий проект неправильно обрабатывает первичные и вторичные контроллеры представлений. Это то, что влияет на представления, из-за неправильного отображения стека контроллера навигации. –

+0

Я изменил свой вопрос, чтобы включить код AppDelegate. Благодарю. –