UISplitViewController и сложная иерархия представлений
Я делаю демонстрацию технологии iPad и столкнулся с серьезной технической проблемой.
У меня есть концепция приложения, которая использует UISplitViewController, но НЕ как основной контроллер для всего приложения.
Поток приложения можно описать примерно так:
Главный экран (UIViewController) List->Detail "Каталог" (UISplitViewController) Экран сверхвысокой детализации (UIViewController, но, возможно, также может быть дочерним для SplitView).
Проблема в потоке между Домом и Каталогом. Как только представление UISplitViewController добавляется в окно UIWindow, оно начинает выбрасывать его.
Проблема может быть кратко изложена в этом:
Когда UISplitView генерирует всплывающее представление, оно, как представляется, затем привязывается к своему родительскому представлению. После удаления UISplitView из подпредставлений UIWindow вы получите исключение CoreGraphics, и представление не удастся удалить.
При добавлении других представлений (предположительно, в данном случае, домашнего экрана, на который вы возвращаетесь) они не автоматически поворачиваются, вместо этого UISplitView, который не удалось удалить из-за исключения CG, продолжает вместо этого реагировать на ротацию, вызывая ужасные ошибки рендеринга, которые нельзя просто "устранить". На этом этапе добавление любых представлений, даже повторное добавление SplitView, вызывает каскад ошибок рендеринга.
Затем я попытался просто оставить SplitView когда-либо представленным как "нижний" вид и продолжать добавлять и удалять домашний экран сверху, но это не удается, поскольку SplitView доминирует над вызовами изменения ориентации, и домашний экран не будет вращаться, даже если вы позвоните [homeScreen intoFirstResponder]
Вы не можете поместить SplitView в иерархию, такую как UINavigationController, вы получите прямую ошибку времени выполнения, так что эта опция не будет рассмотрена. Модалы просто выглядят плохо и в любом случае обескураживают.
В настоящее время я предполагаю, что единственный правильный способ решения этой проблемы - это так или иначе "разоружить" UISplitViewController, чтобы его можно было удалить из родительского представления, не создавая необработанное исключение, но я понятия не имею, как.
Если вы хотите увидеть приложение, которое делает именно то, что мне нужно, проверьте GILT Groupe в магазине приложений iPad. Они сделали это, но, кажется, запрограммировали весь набор пользовательских переходов.
Помощь будет принята с благодарностью.
6 ответов
Я решил это для себя... на самом деле обошел стороной..., представив все другие возможные полноэкранные виды в качестве модальностей SplitView...
Это неприемлемый способ сделать что-то в моей книге, но Apple оставляет вам небольшой выбор, если вы хотите использовать SplitView только "иногда" в приложении.
Apple заявляет:
Представление контроллера разделенного представления всегда должно быть установлено как корневое представление окна вашего приложения. Вы никогда не должны представлять разделенное представление внутри интерфейса навигации или панели вкладок.
Это означает, что это должно быть корневое представление, а не подпредставление другого представления. Хотя они добавляют:
Вы никогда не должны представлять разделенное представление внутри интерфейса навигации или панели вкладок
Это не означает, что вы можете добавить его как подпредставление любого другого контроллера. (извиняюсь)
У меня есть ощущение, что то, что вы испытываете, является побочным продуктом попытки сделать это. Я на самом деле удивлен, что приложение GILT Groupe не было отклонено. Apple в последнее время довольно строго соблюдает эти правила HIG. Они (как вы уже узнали) вызывают довольно неприятную ошибку во время выполнения, когда вы пытаетесь добавить их в NavigationController.
Я добился определенного успеха, создав второе окно UIWindow. Я связываю UISplitViewController с этим и переключаю его в главное окно, когда хочу показать splitview. Кажется, они работают так, как я хотел, за исключением небольшой задержки в поворотах и сообщения журнала о "wait_fences".
Я борюсь с этой же проблемой. Я пробовал разные вещи, тыкая в UISplitViewController как черный ящик, и вижу, как он реагирует.
Кажется, я нашел решение для моего дела, которое, кажется, работает удовлетворительно.
Похоже, ключ к этому заключается в том, что первое представление, добавленное в окно UIWindow, является единственным представлением, правильно инициализированным. Все проблемы, которые у меня были, как правило, связаны с неправильным уведомлением об ориентации устройства. Первое добавленное представление, по-видимому, правильно настроено.
В моем случае я не хотел UISplitView в качестве первого представления. Следующее работает для меня.
Приложение делегата приложения: метод didFinishLaunching является специальным. Добавление вида в UIWindow должно произойти здесь. Если это сделано в другом месте, оно не будет настроено должным образом.
По сути, волшебный соус - это разделенный вид, который будет первым видом, добавленным к окну. Тогда можно удалить его, пока вы сохраняете UISplitViewController. С этого момента вы можете поменять местами другие представления, включая UISplitView, и большинство вещей, кажется, в порядке.
Я все еще сталкиваюсь с несколькими проблемами. Всплывающие окна в представлениях, отличных от разделенного вида, путаются в рамах видов и расположении кнопок панели инструментов и отображаются в неверном месте. Я помещаю тогда в определенное место, и это, кажется, обрабатывает тот случай.
Если всплывающее окно на разделенном виде все еще отображается, и вы пытаетесь просмотреть другой вид, ориентация второго вида сбивается с толку и отображается сбоку. Если этот вид доступен до отображения всплывающего окна, все в порядке. Я исправил это, вручную отключив всплывающее окно, прежде чем переключаться на любое другое представление.
Вот код, если это помогает. Все контроллеры являются переменными экземпляра appDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// This also seems to work as good magic. Seems to set orientation and size properties that persist.
[window addSubview:splitViewController.view];
[splitViewController.view removeFromSuperview];
[self switchToNewViewController:firstController];
[window makeKeyAndVisible];
return TRUE;
}
- (void)switchToNewViewController:(UIViewController *)newViewController {
[popoverController dismissPopoverAnimated:FALSE];
if (newViewController != currentViewController) {
[currentViewController removeFromSuperview];
currentViewController = newViewController;
[window addSubView:newViewController.view];
}
}
Если вы не разрабатываете для устройств с джейлбрейком, то сгибать правила и пожелания яблок не очень хорошая идея. Подобно состоянию Jann и Jasconius выше, это означает сохранение корневого представления контроллера splitView, не чрезмерное использование модальных (расплывчатых) и не использование нескольких окон.
Кроме того, приложение Gilt доступно только в США.
Я тоже пытался найти решение и закончил тем, что программно удалял виды из окна, о чем говорит Туаннд, но ошибка рендеринга ландшафта непростительна.
@Jasconius, какое максимальное количество модалов вы представляете в любое время?
Просто хотел сказать, что я сталкивался с этими же проблемами, нашел эту тему на форуме и следовал совету из g051051 выше. Это прекрасно работает для меня. Я не вижу ни глюка, ни сообщений о wait_fences в консоли устройства.
Я просто использовал IB, чтобы создать два объекта UIWindow в основной XIB, как обычно созданный UISplitViewController, а затем также экземпляр моего другого контроллера, производного от UIViewController (который я использую для полноэкранного отображения). Я просто подключил их, подключив rootViewController для каждого UIWindow к соответствующему контроллеру.
В приложении: didLaunch...: метод Я могу решить, какое окно отправить методу makeKeyAndVisible, а какое - скрытому. Когда пользователь хочет переключаться назад и вперед, я просто должен отправить makeKeyAndVisible одному и установить скрытое свойство для другого, и это все, что нужно сделать.
Как указано, все относящиеся к ротации сообщения отправляются каждому контроллеру соответствующим образом, независимо от того, какое из них связано с текущим видимым окном.
Во всяком случае, прекрасно работает для меня, и на самом деле довольно легко настроить.