С незапамятных времен Split View Controller был доступен только на iPad. Начиная с iOS 8, он теперь работает и на iPad, и на iPhone.
Это произошло потому, что в iOS 8 Apple представила, а в iOS 9 развивает дальше адаптивный пользовательский интерфейс (UI), который включает в себя использование Size Classes и адаптивную разметку Auto Layout. Согласно новой философии, пользовательский интерфейс может достаточно быстро настраиваться для любого типа прибора в зависимости от того, какой Size Class (класс размера) имеет его экран.
Адаптивный вариант UI для Photomania Universal URL, функционирующий в iOS 9, находится на Github. Давайте посмотрим, как он был создан.
Для классификации различных приборов в iOS 8 было введено понятие Size classes. Они заменяют как UIInterfaceOrientation, так и UIUserInterfaceIdiom. Всего четыре size classes:
- Horizontal Regular
- Horizontal Compact
- Vertical Regular
- Vertical Compact
Ваш View Controller всегда существует в среде Size class с определенной шириной (width) и высотой ( height). В настоящий момент size class может быть либо Compact, либо Regular.
Полноразмерные View Controllers on iPad всегда являются Regular по обоим направлениям (горизонтальному и вертикальному). На всех iPhones перед появлением iPhone 6+ и iPhone 6s+, горизонтальный размер всегда был Compact (и в портретном, и в ландшафтном режимах), а вертикальный размер был Regular в портретном режиме и Compact в ландшафтном режиме. С появлением больших iPhones 6+ и iPhones 6s+ у них, в отличие от других iPhones, ширина стала Regular в ландшафтном режиме, что и дало основание распространить применение Split View Controller на iPhones 6+ и iPhones 6s+ в ландшафтном режиме.
Будет не очень удобно, если я буду для всех своих приложений создавать различные интерфейсы для всех 4-х ситуаций. Поэтому, фактически, в Xcode у нас есть еще один Size Class, называемый Ayn (wAny hAny), который мы используем при проектировании универсального приложения в Xcode 7.
В iOS 7 нам приходилось при создании универсального приложения cоздавать два совершенно разных интерфейса, используя совершенно разные типы Controllers ( ниже представлены storyboards приложения Photomania Universal URL, спроектированные в iOS 7):
Split View Controller на iPad
Main_iPad.storyboard
Navigation Controller на iPhone
Main_iPhone.storyboard
В iOS 8 Split View Controller становится адаптивным. Это означает, что единственный Split View Controller может управлять двумя этими архитектурами для двух типов приборов.
Для получения адаптивного интерфейса нужно выбрать файл storyboard и указать в Инспекторе Файла режим Size Class и Auto Layout:
И наш storyboard теперь будет соответствовать адаптивному интерфейсу.
Адаптивная storyboard очень похожа на storyboard для iPad в iOS 7, за исключением двух вещей:
- размеры всех экранных фрагментов одинаковые и соответствуют универсальному в Xcode классу wAny hAny,
- появился новый адаптивный segue типа Show Detail Segue, который помогает Split View Controller осуществлять сразу две функции: “скольжение” как в Navigation Controller и «переезд» к Detail как это принято в Split View Controller.
Нам придется внести небольшие поправки в стандартное адаптивном функционирование Split View Controller для придания ему привычного нам вида. Чтобы понять необходимость этих поправок, будем экспериментировать не с громоздким приложения Photomania, а с очень простым приложением, представляющим списком стран (Master). При выборе определенной страны приложение показывает ее флаг (Detail). Окончательный вариант простейшего приложения SplitViewCountry находится на Github. Но мы будем создавать его с «чистого листа».
Открываем новый проект для универсального приложения для Objective-C и называем его SplitViewCountry
и используем шаблон Single View Application ( именно этот шаблон, а не Master-Detail Application, который мы будем исследовать позже). Будем проектировать наше приложение с «чистого листа». Поэтому уберем со storyboard единственный экранный фрагмент View Controller и оставим storyboard совершенно пустой. Удалим также файлы ViewController.h и ViewController.m.
Перетянем из палитры объектов на storyboard Split View Controller
Устанавливаем Split View Controller в качестве стартового экранного фрагмента.
Добавляем два новых класса SelectCountryTableViewController (наследует от UITableViewController) и CountryViewController (наследует от обычного UIViewController) в наш проект для Master и Detail. Устанавливаем эти классы на storyboard.
Master представляет собой таблицу стран.
Detail показывает флаг определенной страны.
На Detail добавлена метка, которая центрируется по горизонтали и вертикали с помощью системы Autolayout. Эта метка будет показывать флаг выбранной страны, а в случае, если страна не задана, будет размещаться такой неопределенный флаг.
Для Master используется класс SelectCountryTableViewController, который содержит определение Модели (это просто массив стран) и реализацию методов делегата Data Source для TableView.
SelectCountryTableViewController.m
Для Detail используется класс ContryViewController. Он показывает метку с флагом страны, которая устанавливается извне с помощью Модели country.
ContryViewController.h
ContryViewController.m
Связь Master и Detail (то есть передача страны country для показа флага) осуществляется классическим для Split View Controller способом с помощью метода делегата Table View.
SelectCountryTableViewController.m
Напоминаем, что storyboard осталась почти неизменной по сравнению с той, которую мы вытянули из Палитры Объектов, никакие элементы пользовательского интерфейса и segues не добавлялись, были изменены только пользовательские классы для Master и Detail
Запускаем приложение на iPad в портретном режиме
Появляется практически пустой экран с изображением флага отсутствующей страны на Detail, и даже непонятно, что делать. Пользователь должен каким-то магическим способом догадаться, что работает жест swipe, который и покажет нам Master, то есть экранный фрагмент со списком стран. Дальше можно выбирать страну и экран с флагом будет автоматически обновляться. Все работает, но отсутствует заголовок Detail и нет возвратной кнопки в Master.
Запускаем приложение на iPad в ландшафтном режиме.
Все работает. При изменении страны флаги обновляются.
Запускаем приложение на iPhone 6+ в портретном режиме
Появляется почти такой же экран, как и в случае с iPad с изображением флага отсутствующей страны на Detail, но есть возвратная кнопка, призывающая нас выбрать страну. Нажимаем на эту кнопку, и действительно попадаем в Master, то есть экранный фрагмент со списком стран. Дальше можно выбирать страну и ничего не происходит. Этот режим не работает, так как нам не удается достичь Detail .
Переходим в ландшафтный режим на iPhone 6+
Все работает. Флаги обновляются.
Какой можно сделать вывод из этих экспериментов?
Если прибор имеет Size Class — Regular (iPad в портретном и ландшафтном режимах и iPhone 6+ в ландшафтном режиме), то все работает, то есть происходит обновление флагов при изменении страны. При этом на экране одновременно находятся и Master, и Detail. Этот режим назван expanded для адаптивного Split View Controller.
Если прибор имеет Size Class — Compact ( iPhone 6+ в портретном режиме, все другие iPhones в портретном и ландшафтном режимах), то ничего не работает, то есть не только не происходит обновление флагов при изменении страны, но мы вообще не попадает на Detail. В случае Compact Size Class на экране находится только один MVC: либо Master, либо Detail, поэтому этот режим назван collapsed для адаптивного Split View Controller.
Причем, если мы включим отладочный режим для режима collapsed, то увидим, что в методе didSelectRowAtIndexPath: делегата UITableViewDelegate, Detail определяется как UINavigationController, но в стэке у него только SelectCountryTableViewController. Нужно как-то поместить в UINavigationController стэк CountryViewController, тогда удастся достичь Detail.
Такую работу и даже больше, выполняет новый segue типа Show Detail. В скобках на картинке, представленной ниже, в Инспекторе Атрибутов дается уточнение, что это Replace segue, а это означает, что Detail этого Split View Controller будет замещаться новым экземпляром MVC. Это очень важно для дальнейшего понимания.
Давайте разместим segue типа Show Detail на нашей storyboard и назовем его «Show flag».
Как и всякий другой segue, этот segue нуждается в подготовке, которая должна проводится с учетом того, что destinationViewController для этого segue будет разным в зависимости от Size Class : для Regular — это CountryViewController, а для Compact — это UINavigationController, в стэке которого на самом верху находится CountryViewController.
Нам придется внести некоторые изменения в CountryViewController, так как при использовании segue происходит полная замена Detail новым MVC, а prepareForSegue работает до полной загрузки CountryViewController и установка нового значения Модели может не обновить до конца пользовательский интерфейс из-за того, что некоторые outlets еще не установлены. Поэтому нам нужно сделать обновление UI с помощью функции updateUI и в случае установки нового значения Модели country, и при загрузке CountryViewController:
Запускаем приложение на iPhone 6+ в портретном режиме (раньше в этом режиме приложение не работало).
Также как и раньше, перед нами появляется экран с изображением флага отсутствующей страны на Detail и возвратной кнопкой, призывающей нас выбрать страну. Нажимаем на эту кнопку, и действительно попадаем в экранный фрагмент со списком стран. Дальше можно выбирать страну, и мы получаем флаг этой страны. Теперь этот режим работает. Но мало этого, мы получили заголовок (страну) на Detail, который появляется для Compact Size Class благодаря действию механизма стэка для Navigation Controller. Для Regular Size Class заголовок на Detai, по-прежнему отсутствует, так как там работает «родной» механизм Split View Controller.
Таким образом, благодаря наличие Navigation Controller со стороны Master и Show Detail segue мы получили работающий адаптивный Split View Controller. Он работает как на iPad, так и на любых типах iPhone. На Regular экранах он работает в режиме expanded (Master и Detail одновременно на экране), а на Compact экранах он работает в режиме collapsed (только один View Controller на экране: либо Master, либо Detail ).
Мы получили одну storyboard, которая работает на обоих платформах (iPhone и iPad) и автоматически адаптируется.
Однако хочется иметь привычный заголовок на Detail и для Regular Size Class (iPad в портретном и ландшафтном режимах и iPhone 6+ в ландшафтном режиме). Мы знаем как этого добиться — нужно вставить Detail в Navigation Controller.
Теперь заголовок для Regular Size Class появился на навигационной панели
Кроме заголовка на навигационной панели можно разместить возвратную кнопку и специальную кнопку смены режимов работы Split View Controller.
Для этого необходимо в методе prepareForSegue подготовки segue типа Show Detail разместить кнопки на навигационной панели в качестве левой кнопки навигационной панели
SelectCountryTableViewController.m
Для того, чтобы эти кнопки действовали при старте приложения аналогичный код нужно добавить в AppDelegate.m
В результате мы имеем необходимую возвратную кнопку для iPad в портретном режиме и кнопку переключения режимов для iPhone 6+ в ландшафтном режиме.
Теперь работу Split View Controller для Regular Size Class можно считать удовлетворительной.
Что нас не устраивает в работе Compact Size Class? На iPhones работа должна сразу начинаться с показа Master и дальше двигаться последовательно в сторону Detail c помощью механизма Navigation Controller. Это обеспечивается методами делегата SplitViewControllerDelegate, один из которых мы сейчас реализуем в AppDelegate. Вначале мы подтверждаем протокол UISplitViewControllerDelegate:
AppDelegate.m
И, наконец, реализуем метод collapseSecondaryViewController:ontoPrimaryViewController: делегата UISplitViewControllerDelegate, который срабатывает при переходе в collapsed режим, когда на экране должен остаться только один View Controller, и он спрашивает нас, нужно ли отбросить Detail. Если мы отвечаем YES, то на экране в collapsed режиме остается только Master, если NO — то Detail. Мы хотим иметь Master только при старте, то есть когда Detail — это Navigation Controller, его топовым View Controller в стэке является CountryViewController , Модель которого country имеет значение равное nil.
Стартуем iPhone 6+ в портретном режиме
Стартуем iPhone 5s в ландшафтном режиме
Теперь наш адаптивный интерфейс работает как нужно, то есть для Compact Size Class (все iPhones и iPhone 6+ в портретной режиме) мы стартуем со списка стран.
Итак, настройка адаптивного Split View Controller завершена. Окончательный вариант простейшего приложения SplitViewCountry находится на Github.
Подведем итог нашим действиям:
Шаг 1. Перетаскивая Split View Controller из Палитры объектов.
Шаг 2. Добавляем segue Show Detail
Шаг 3. Настраиваем для segue метод prepareForSegue с учетом того, что destinationViewController для этого segue будет разным в зависимости от Size Class : для Regular это CountryViewController, а для Compact это UINavigationController, в стэке которого на самом верху находится CountryViewController.
Шаг 4. Добавляем кнопки на навигационную панель в методе prepareForSegue подготовки segue типа Show Detail и в AppDelegate.
Шаг 5. Реализуем в AppDelegate метод collapseSecondaryViewController:ontoPrimaryViewController: делегата UISplitViewControllerDelegate, который срабатывает при переходе в collapsed режим, когда на экране должен остаться только один View Controller и он спрашивает нас, нужно ли отбросить Detail.
Можно обойтись без этих 5 шагов и получить точно такой же код и UI сразу же, если воспользоваться прекрасным Master-Detail шаблоном приложения, в котором уже есть и Show Detail segue и Navigation Controller и весь необходимый код.
Но пойдем дальше и сравним полученную в простейшем приложении SplitViewCountry storyboard, со storyboard Photomania, которую мы привели в начале этого поста. Мы поймем, что в Photomania две Table View Controllers в Master: одна — для фотографов, другая — для списка его фотографий. Поэтому нам придется продолжить эксперименты с нашим маленьким примером и добавим еще один экранный фрагмент Table View Controller для «Континентов». Теперь наш пользовательский интерфейс выглядит следующим образом:
Все будет работать прекрасно, за исключением одной ситуации, когда iPhone 6+ переходит из портретного режима в ландшафтный (то есть из collapsed режима в expanded), и при этом его экран в портретном режиме показывает Список Стран на месте Detail, а вовсе не флаг выбранной страны:
При переходе из collapsed режима, когда на экране только один View Controller, в режим expanded (Master и Detail одновременно на экране), адаптивный Split View Controller берет текущий экран в качестве Detail по умолчанию. А это совсем не то, что нам нужно. С помощью другого метода separateSecondaryViewControllerFromPrimaryViewController: делегата UISplitViewControllerDelegate, нам самим предлагается произвести нужную настройку
Метод separateSecondaryViewControllerFromPrimaryViewController: спрашивает вас, какой View Controller следует взять в качестве Detail. В нашей ситуации, когда primaryViewController — это Страны, нам неоткуда взять CountryViewController (изображение флага) как только со storyboard. Далее мы делаем небольшую настройку нашего Detail.: добавляет кнопки на навигационную панель и выставляем флаг страны, первой в списке стран.
Теперь все работает правильно
Полученный пример, простейшее приложении SplitViewCountry, можно рассматривать как шаблон для построения адаптивного приложения с такой конфигурацией storyboard, как в Photomania Universal URL.
Мы можем еще немного улучшить работу Split View Controller для iPad, задав преимущественный режим показа UISplitViewControllerDisplayModeAllVisible:
Что означает preferredDisplayMode? Это свойство определяет режим показа Split View Controller, который вы предпочтительно хотите использовать. Split View Controller делает все возможное, чтобы настроить интерфейс соответствующим образом, но может использовать и другой режим показа, если, например, будет недостаточно места для показа в заданном вами предпочтительном режиме.
Установка значения этого свойства в UISplitViewControllerDisplayModeAutomatic заставляет выбирать наиболее подходящий режим для текущего доступного пространства. На iPad это приводит к использованию режима UISplitViewControllerDisplayModePrimaryOverlay в портретной ориентации и UISplitViewControllerDisplayModeAllVisible в ландшафтной ориентации. По умолчанию значение этого свойства равно UISplitViewControllerDisplayModeAutomatic.
Задавая режим показа UISplitViewControllerDisplayModeAllVisible, мы, фактически, влияем только на показ Split View Controller на iPad в портретном режиме
в ландшафтном режиме тоже есть небольшие изменения: появляется кнопка переключения режимов показа, которая раньше на iPad не показывалась
Я привела еще две закомментированные строки кода
// splitViewController.preferredPrimaryColumnWidthFraction = 0.5;
// splitViewController.maximumPrimaryColumnWidth = 512;
Если вы раскомментируете эти строки, то сможете регулировать ширину столбцов для Master и Detail. Вы можете использовать свойство preferredPrimaryColumnWidthFraction, которое принимает значение от 0.0 до 1.0 , чтобы представить долю от общей ширины экрана, которую занимает Master. Например, значение 0.4 представляет 40% текущей ширины. По умолчанию это свойство принимает значение UISplitViewControllerAutomaticDimension, которое приводит к подходящей ширине Master, выбираемой Split View Controller.
Действительная ширина Master ограничивается значениями в диапазоне minimumPrimaryColumnWidth и maximumPrimaryColumnWidth. Split View Controller будет делает все возможное, чтобы настроить интерфейс соответственно заданным вами значениям свойств, но может поменять значения на другие в зависимости от располагаемого пространства. Вы можете получить действительную ширину Master с помощью свойства primaryColumnWidth.
Давайте распространим наши достижения на наше адаптивное приложение Photomania Universal URL. Мы уже получили storyboard в нужном виде с Show Detail segue:
Делаем подготовку нового segue типа Show Detail в коде класса PhotosCDTVC таким образом, чтобы учесть присутствие Navigation Controller, предшествующего Detail, и добавить имеющуюся у Split View Controller кнопку displayModeButtonItem на навигационную панель. :
Добавляем кнопки на навигационную панель в PhotomaniaAppDelegate для появления их при старте приложения:
Подтверждаем протокол UISplitViewControllerDelegate:
Затем назначаем себя делегатом:
PhotomaniaAppDelegate.m
И, наконец, реализуем метод collapseSecondaryViewController:ontoPrimaryViewController: делегата UISplitViewControllerDelegate, который спрашивает нас, нужно ли отвергать Detail в collapsed режиме:
В нашем случае, мы оставляем на экране Master, если Detail — это Navigation Controller, его топовым View Controller является ImageViewController и Модель imageURL имеет значение, равное nil.
Реализуем другой метод separateSecondaryViewControllerFromPrimaryViewController: делегата UISplitViewControllerDelegate, который срабатывает при переходе из collapsed режима в expanded (Master и Detail одновременно на экране). В нашей ситуации, когда primaryViewController представляет собой PhotosByPhotographerCDTVC, берем ImageViewController (изображение фотографии) со storyboard и настраиваем его на автоматически выбираемую фотографию в таблице фотографий, которая может быть любой случайной из списка, но мы выбираем первую фотографию в таблице фотографий PhotosByPhotographerCDTVC.
Можем задать режим показа UISplitViewControllerDisplayModeAllVisible:
Адаптивный вариант UI для Photomania Universal URL, функционирующий в iOS 9, находится на Github.
Popover
Продолжим эксперименты с нашим маленьким примером и добавим еще один экранный фрагмент Capital View Controller на storyboard, который будет показывать столицу выбранной страны в Popover «окошке» при нажатии кнопки «Столица» на навигационной панели. Новый экранный фрагмент Capital View Controller активизирует свою работу с помощью кнопки «Столица»и segue типа Presents as Popover.
В iOS 9 класс UIPopoverController упразднен. Вместо него в iOS 9 используется UIPopoverPresentationController, который доступен с iOS 8. Концепция Popover осталась той же самой: нам необходим View Controller, как содержимое, которое показывается внутри Popover, но сам по себе Popover — не UIViewController. Он появляется на экране, используя так называемый механизм Popover Presentation Controller.
Относительно Popover интересно еще то, что помимо того, что хотя он сам по себе не является MVC, он все же использует segues и все, что с ними связано. Он использует CTRL-перетягивание к некоторому View Controller, и вы все также получаете возможность выполнять метод prepareForSegue. И это выглядит совершенно точно также, хотя у него нет своего собственного View Controller. Popover все равно использует segues, чтобы вызвать появление презентуемого им View Controller.
Следует обратить внимание на некоторые возможности при подготовки segue для Popover.
Одна из них — это то, что внутри вашего prepareForSegue вы можете получить то, что называется Presentation Controller. И Presentation Controller может рассказать вам о том, какие вещи (например, кнопка) заставили “всплыть” Popover. Вы можете даже конфигурировать презентацию Popover. Например, вы можете сказать, что не хотите, чтобы Popover “всплывала” слева от чего-то. Я хочу, чтобы Popover всегда “всплывала” справа от чего-то. Вы можете этим управлять.
Еще более интересно то, что вы можете использовать делегата (delegate) Presentation Controller.
Используя Presentation Controller делегата, вы можете воздействовать на то, как Popover будет адаптироваться на iPhone. Popover на iPad “всплывает” ввиде маленького окошка. На iPhone Popover адаптируется и превращается вместо маленького окошка в модальное окно на полный экран. Оно не “всплывает” как что-то маленькое на iPhone. Почему? Потому что экран iPhone значительно меньше, и если “всплывающая” вещь реально большая, то может не быть способа избавиться от нее или сделать ее подходящей размеру экрана. Но если вы представите ее модально на весь экран, то она точно подойдет по размеру экрана. Адаптация делается автоматически. iOS автоматически делает эту адаптацию вместо вас, также как автоматически адаптируется Split View и Navigation Controller, если вы создаете вашу storyboard прямо на iPhone. Но используя делегата Presentation Controller Delegate, вы можете воздействовать на эту адаптацию.
Давайте посмотрим, как в методе prepareForSegue вы можете получить этот Popover Presentation Controller, и как вы можете делать что-то с этим, например, устанавливать делегата.
Код для подготовки segue в методе prepareForSegue будет отличаться от того, что был в iOS 7, когда мы получали экземпляр упраздненного в iOS 9 класса UIPopoverController непосредственно из segue. В iOS 9 мы будем получать экземпляр нового класса UIPopoverPresentationController не из segue, а непосредственно из segue.destinationViewController:
Мы можем использовать его делегата
ppс.delegate = self;
если подтвердим протокол UIPopoverPresentationControllerDelegate
CountryViewController.m
Протокол нам нужен для следующих целей. В iOS 9, когда Popover пытается провести презентацию, он собирается вас спросить, как вы хотите, чтобы я “адаптировал” Popover, если я на iPhone? По умолчанию, мы говорим, что это модальное представление на полный экран (возврат .FullScreen), но вы можете сказать, что вы хотите UIModalPresentationStyle.None, что означает, что адаптации не будет. То есть презентация на iPhone будет в точности такая же, как и на iPad. Для маленького Popover это имеет большой смысл. Мы можем “выключить” поведение “адаптации”, реализовав метод делегата UIPopoverPresentationControllerDelegate
CountryViewController.m
Последняя и очень важная вещь, касающаяся Popover — это размер “всплывающего” окна.
Вам действительно нравится, когда появляется абсолютно идеально подогнанное к размеру MVC. Потому что MVC могут быть разного размера. В любом случае вы хотели бы реально управлять размером. В объектно-ориентированном мире система спрашивает MVC, которое находится в Popover, какой размер этот MVC предпочитает? Какого размера ты хочешь быть? Потому что реально только само MVC может знать, какой размер может быть предпочтительным или идеальным. Но это только рекомендация, потому что у Popover тоже есть некоторые ограничения (constraints). Потому что Popover может появляться на экране только в определенном месте, экран должен быть достаточно большим, стрелочки могут иметь определенные направления, у Popover много ограничений, с которыми надо работать.
Но он все равно спрашивает MVC, которое размещает внутри, чем оно хочет быть? Есть специальное свойство в вашем UIViewController:
@property(nonatomic) CGSize preferredContentSize
Вы можете переопределить это свойство и вернуть предпочитаемый размер. Если ваш предпочтительный размер всегда один и тот же размер, вы можете просто его установить. Если вам нужно рассчитать предпочтительный размер на основании его содержимого, что вы можете сделать это следующим образом:
CapitalViewController.m
Вариант простейшего приложения SplitViewCountry c Popover находится на Github.
Есть одна проблема, связанная с работой Popover в портретном режиме на iPad. Если я перейду в портретный режим и покажу «Столицу» Санта-Фа-Де-Богота для Колумбии. Затем я кликну на Континенты в левой части навигационной панели и выберу другую страну — Чили … Вы видите, что столица Санта-Фа-Де-Богота не ушла, осталась на экране, хотя я полагала, что если я кликну где-нибудь за пределами Popover, то Popover уйдет.
Ответ заключается в том, что, если вы кликаете на ту же самую панель, где находится кнопка “Столица”, то вам разрешается взаимодействовать со всем, что там находится, то есть кликать на любых кнопках и Popover не уйдет. Это вещь имеет отношение к passthroughViews. Целая навигационная панель является частью passthroughViews, и реально плохая вещь заключается в том, что, если я кликну на другой стране, то изображение флага этой страны обновится, а Popover со Столицей — нет. Мне по-прежнему будет показываться Столица старой страны. Это действительно очень плохо.
Эту проблему в коде будем решать следующим образом. Каждый раз, когда кто-то устанавливает мой country в методе setCountry, я буду убирать (dismiss) любой Popover, который у меня есть.
CountryViewController.m
Теперь ситуация исправилась
Вариант простейшего приложения SplitViewCountry cо всеми нюансами Popover находится на Github.
Давайте вернемся к адаптивному варианту UI для Photomania Universal URL, функционирующий в iOS 9, и посмотрим, какие нам нужно сделать изменения для Popover.
ImageViewController.m
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
URLViewController.m
Адаптивный вариант UI для Photomania Universal URL, функционирующий в iOS 9 c Popover, находится на Github.
Классно все обяснили, большое спасибо