Адаптивный переход в раскадровке Xcode 6. Является ли push устаревшим?

121

Конструктор интерфейса Xcode 6 по умолчанию имеет новый флажок «использовать классы размера». Это делает представления адаптивными. введите описание изображения здесь

Когда я пытаюсь сделать переход между двумя представлениями в моей раскадровке, у меня появляются новые возможности: введите описание изображения здесь

вместо старого:

введите описание изображения здесь

Теперь у нас есть «показать» и «представить модально» вместо «push» и «модально». Старые параметры отмечены как устаревшие. Я выбрал вариант «показать», потому что в настройках перехода он называется «показать (например, нажать)».

введите описание изображения здесь

Но толчка это не дает. Анимация перехода выглядит как слайд снизу (модальный), а панель навигации исчезает.

Вопрос: как заставить "шоу" работать как толчок? Возможно ли это, или я должен использовать вместо этого "push (устаревший)"? Где я могу найти информацию о новых типах переходов? Единственное, что я нашел в библиотеке разработчика iOS8, - это раскадровки, которые помогут вам разработать свой пользовательский интерфейс, но нет никакой информации о переходе «показать».

ОБНОВИТЬ

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

if ( [segue isKindOfClass: [SWRevealViewControllerSegue class]] ) {
    SWRevealViewControllerSegue *swSegue = (SWRevealViewControllerSegue*) segue;
    
    swSegue.performBlock = ^(SWRevealViewControllerSegue* rvc_segue, UIViewController* svc, UIViewController* dvc) {
        
        UINavigationController* navController = (UINavigationController*)self.revealViewController.frontViewController;
        [navController setViewControllers: @[dvc] animated: NO ];
        [self.revealViewController setFrontViewPosition: FrontViewPositionLeft animated: YES];
    };
    
}

После этого я пытаюсь нажать NewViewController после MainViewController введите описание изображения здесь

ОБНОВЛЕНИЕ 2:

У меня вроде только iOS 7, проблема iOS 7.1.

Джон Какон
источник

Ответы:

97

Да, используйте "Показать" вместо "Нажать"

Как сделать так, чтобы "шоу" работало как толчок? Возможно ли это, или я должен использовать вместо этого "push (depricated)"?

Должно; это делает для меня. Я использую Xcode 6 beta 2, и для тестирования я использовал шаблон единого представления (вызывая предварительно созданный контроллер представления в IB 'VC_A'). Затем я добавил еще один контроллер представления (VC_B). Затем я добавил кнопку на VC_A, чтобы показать VC_B и еще одну из VC_B обратно в VC_A. Когда я добавляю контроллер навигации в качестве исходного контроллера представления в раскадровке и делаю VC_A корневымViewController, и «push», и «show» имеют одинаковый эффект. Если у меня нет начального контроллера навигации и я использую «показать», я получаю то, что вы описали в том, что VC_B выполняет скольжение снизу вверх. Если я пытаюсь «нажать», я получаю сбой, так как для этого мне нужен контроллер навигации.

Где я могу найти информацию о новых типах переходов?

Так что я нашел некоторую информацию в «Что нового в Interface Builder» сессии здесь . Если вы посмотрите на слайды, вы увидите один слайд (41), в котором упоминается изменение. При просмотре этого сеансового видео вы можете перейти к минуте 38:00, где они начинают говорить об адаптивных переходах. Они действительно объясняют, что адаптивный переход «показать», например, принимает во внимание контекст при принятии решения о том, как сделать презентацию нового контроллера представления.

Спенсер Холл
источник
Спасибо за ваш ответ. Я попытался создать новый проект, и «шоу» действительно работает как push с контроллером навигации. В моем проекте у меня сложная структура с боковой панелью из этого урока appcoda.com/ios-programming-sidebar-navigation-menu и push работает, а show - нет. Может быть причина в том, что я повторно использую контроллер навигации. Я обновил свой вопрос кодом повторного использования.
John Kakon
Итак, первое, что я вижу, глядя на ваше обновление, - это то, что вы используете ожидаемый пользовательский переход: 'SWRevealViewControllerSegue', поэтому да, вероятно, нет смысла использовать 'show' или 'push' в вашем случае, поскольку они встроены в segues, тогда как вы хотите запустить свой собственный код. Когда я загружаю образец проекта, он даже показывает выбор «custom» на сегментах в файле раскадровки.
Спенсер Холл,
Я не имел в виду этот переход. Я говорил о создании нового UIViewController рядом с «MainViewController» (у него есть контроллер навигации, и мое «обновление» показывает только, как мне его туда получить) и пытается протолкнуть новый View в MainViewController. Снимок экрана раскадровки Буду признателен, если вы включите «использовать классы размера» в примере проекта, создадите NewViewController и попытаетесь установить переход между MainViewController и NewViewController с помощью «show». Вы увидите, о чем я говорю.
John Kakon
Сделал это только сейчас, и, по крайней мере, для меня «шоу» работало так же, как «толчок».
Spencer Hall
9
Вы можете обойти ошибку, убедившись, что все пути в ваш контроллер представления имеют UINavigationController в своем корне. Даже если это означает размещение UINavigationController в вашей раскадровке, к которому никогда не будет доступа. Похоже, что проводка используется для определения поведения.
Скотт Робертсон
33

Уже есть принятый ответ, но я хотел бы дать немного больше информации, возможно, информации, которой раньше не было.

Как упоминалось ранее, сегменты «push» и «modal» устарели и были заменены на «show» и «present modally» соответственно. Согласно документации Apple, новые сегменты были дополнительно разделены на сегменты, которые адаптируются к классам размеров. Старые версии следует использовать только для поддержки версий iOS старше iOS 8.

Документ по следующей ссылке объясняет это и описание всех доступных сегментов, старых и новых.

Добавление перехода между сценами в раскадровке

В случае, если URL-адрес изменится в будущем, для каждого нового перехода приводится следующее объяснение:

Шоу

Представьте содержимое в области деталей или основной области в зависимости от содержимого экрана. Если приложение отображает главное и подробное представление, содержимое помещается в область подробностей. Если приложение отображает только мастер или детали, содержимое помещается поверх текущего стека контроллера представления.

Показать детали

Представьте контент в области подробностей. Если приложение отображает основное и подробное представление, новое содержимое заменяет текущие сведения. Если приложение отображает только мастер или детали, содержимое заменяет верхнюю часть текущего стека контроллера представления.

Присутствует модально

Представьте контент модально. Есть варианты выбора стиля представления (UIModalPresentationStyle) и стиля перехода (UIModalTransitionStyle).

Присутствует как Popover

Представьте контент как всплывающее окно, привязанное к существующему представлению. Существует возможность указать возможные направления стрелки, показанной на одном краю всплывающего окна (UIPopoverArrowDirection). Также есть возможность указать вид привязки.

alondono
источник
24

tldr; Удалите Segue, который не проталкивается правильно, и воссоздайте его в раскадровке, перетащив его из UIView / UIControl на целевой контроллер представления.

В других ответах нет ничего плохого, но этот объясняет, что происходит, как вы можете проверить, что это происходит, и как решить проблему в будущем.

Задний план

В моем случае ни один из моих сегментов шоу не работал, хотя у меня уже был UINavigationController в качестве исходного контроллера представления (с моим содержимым UIViewController в качестве корневого).

Почему и как ломается переход к шоу

Переход «Показать» прерывается, когда с ним связано действие в исходном xml-файле раскадровки. Типичный сценарий, вызывающий это, может быть, если вы переопределили переход из ручного перехода, ранее вызванного в коде. Это оставляет следующие биты в раскадровке xml.

<connections>
    <segue destination="85t-Z1-hxf" kind="show" identifier="ToOptions" action="showDetailViewController:sender:" id="gdZ-IX-KcN">
</connections>

Nota Bene Для просмотра раскадровки как xml; Щелкните правой кнопкой мыши файл раскадровки и выберите «Открыть как»> «Исходный код» . Чтобы вернуться, используйте Open as> Interface Builder - Storyboard

Чтобы учесть любые настраиваемые действия при использовании перехода из раскадровки, можно просто нажать на prepareForSegue и перехватить целевой контроллер представления и вызвать любые методы из этого места. В любом случае, побочный эффект для этой маленькой ошибки (ошибка заключается в том, что когда вы переопределяете переход, он неправильно настроен в xml ~ т.е. действие остается даже после того, как вы измените переход на тот, который работает из UIView (или UIControl) в целевой контроллер представления).

К сожалению, самое прямое решение не удается. Поэтому простое удаление атрибута xml для действия из раскадровки НЕ решит проблему. Вместо этого нужно просто удалить и воссоздать переход в раскадровке.

При воссоздании в раскадровке xml больше не будет действий, связанных с конкретным сегментом, и Show будет выполняться как Push.

Образец XML для правильного перехода к шоу

  <connections>
    <segue destination="RbV-Au-WV9" kind="show" identifier="ToOptions" id="5dm-os-bcS"/>
  </connections>

смягчение

Чтобы предотвратить повторение, нужно просто придерживаться не ручных переходов раскадровки, если это возможно, используя prepareForSegue для добавления необходимых действий на основе контроллера представления назначения. Или, если вам нужно смешивать и сопоставлять, примите меры предосторожности, чтобы убедиться, что ваши сегменты шоу не имеют никаких действий, прикрепленных в xml раскадровки. Если вы имеете дело со старыми проектами, вам следует уделить особое внимание исходному коду раскадровки, поскольку я обнаружил несколько проблем.

Томми К.
источник
3
После нескольких часов это сэкономило мне, вероятно, еще несколько часов. Вот то, что я бы предложил на основе вышеизложенного: Откройте раскадровку как исходный код , найдите kind = "show" и посмотрите, содержит ли строка что-то вроде action = "showDetailViewController: sender:" , если да, удалите все из действия = до закрытия " . У меня действительно огромная раскадровка, и затронутая секвенция не содержала этого параметра действия, но была в другой несвязанной строке. После того, как я удалил действие, все адаптивные секвенции снова заработали, как ожидалось. Простое удаление затронутой секвенции не помогло ' t работает
Маркус
Это меня тоже спасло.
Адам Бардон
1
Удаление атрибута действия в XML сработало для моего друга.
Брент Роял-Гордон
спас меня тоже
Джимми Джордж Томас
Удалил атрибут действия в файле xml, и вуаля, он работает. Я бы никогда не нашел проблему без этого сообщения.
krizzzn
20

Как здесь прокомментировал Скотт Робертсон , это похоже на ошибку в iOS 7.

Похоже, что в iOS 8 переход определяется во время выполнения (правильное поведение), а в iOS 7 переход определяется во время разработки (ошибочное поведение).

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

Примечание: имитации панели навигации для этих целей недостаточно; у вас должен быть контроллер навигации в стеке push-уведомлений.

Чтобы воспроизвести ошибку:

  1. Создайте новую раскадровку, в которой используются классы размеров.
  2. Создайте два контроллера представления (без контроллеров навигации).
  3. Сделайте так, чтобы первый контроллер представления отображал второй контроллер представления через Show (например, Push) перехода связанного с кнопкой.
  4. В коде покажите первый контроллер представления, но встроите его в контроллер навигации с помощью initWithRootViewController:метода.
  5. Запустите приложение на iOS 7.
  6. Нажмите кнопку, которая должна выполнить нажатие.
  7. В iOS 7 вы получите модальный переход вместо push. В iOS 8 вы получите правильное поведение push.

введите описание изображения здесь

Чтобы исправить ошибку:

  1. Добавьте контроллер навигации к раскадровке и установите первый контроллер представления в качестве корневого контроллера представления. (Примечание: добавление второго в качестве контроллера корневого представления НЕ исправит эту ошибку.)
  2. Дайте ему идентификатор нежелательной почты, чтобы подавить предупреждение о недоступности контроллера навигации и задокументировать для себя, что он существует исключительно как обходной путь. (например workaround for show segues in iOS 7).

введите описание изображения здесь

Обратите внимание, как на втором рисунке был добавлен контроллер навигации и что у него нет никаких входящих стрелок (т.е. нет другого способа создать его экземпляр, кроме использования идентификатора контроллера представления).

Senseful
источник
1
Спасибо, трюк с NavigationController сработал для меня, когда я заменил корневой NavigationControllers ViewController-Stack
Питер Пинт
1
Лучшее решение. Спасибо
Илья Голованов
13

Я знаю, что опаздываю с этим, но я хотел поделиться тем, что я узнал. На самом деле это ошибка, которая существует и сегодня (18 декабря 2014 г.).

Я написал об этом статью здесь .

Это легко воспроизводимо; на iOS8 будет работать нормально и даже в iOS7.x до тех пор, пока вы не вставляете программный контроллер представления в стек перед вызовомShow segue.

Если вы отправляете в стек только соединения с раскадровкой, это сработает; но, очевидно, если вы каким-то образом нажмете код, navigationControllerсвойство нажатого UIViewControllerбудетnil и когда вы вызоветеShow он будет считать его модальным, потому что нет навигации для управления стеком.

Единственным обходным решением на данный момент является либо не проталкивание через код (что невозможно), либо использование устаревшего Push .

Подала радар (ссылка на статью). Не стесняйтесь отправлять дубликаты в надежде, что Apple решит эту проблему.

esttorhe
источник
3
Это была моя проблема, спасибо! использование устаревшего push в этом случае кажется меньшим злом.
Моше Готлиб
Другой обходной путь - добавить (неиспользуемый) контроллер навигации в раскадровку. См stackoverflow.com/questions/24184003/...
Senseful
Nop! Это происходит здесь, и причина не в программном подталкивании. В моем случае я выполняю Showпереход, затем на втором Showэтапе он отображается модально. Решение?
Frade
@Frade, можете ли вы ссылаться на репозиторий github, где это можно воспроизвести? Вы используете какую версию iOS?
esttorhe
частный проект .. Это происходит при попытке выполнить (второй) ShowviewController на iOS 7
Frade
2

У меня была такая же проблема с переходами в Xcode 7 и iOS 7.1.2. Показать переходы (новая функция в iOS 8) работает как модальные переходы в iOS 7 и не позволяет вам помещать ваши контроллеры представления в стек контроллера навигации, когда вы определяете тип перехода с помощью Xcode в раскадровке. Вот почему ваш self.navigationController вернет nil, потому что контроллер представления не был помещен в стек, и вы не можете его вставить.

Я не понимаю, почему Apple не добавила никаких уведомлений для этого случая в Xcode, когда вам нужно, чтобы ваше приложение работало на iOS 7. Они говорят, что метод Push устарел, но Show не работает правильно с iOS 7.

Что я сделал для решения проблемы:

Я создал класс MYShowSegue с .h

#import <UIKit/UIKit.h>

@interface MYShowSegue : UIStoryboardSegue

@end

И файл .m только с одним методом выполнения :

#import "MYShowSegue.h"

@implementation MYShowSegue

- (void) perform {

    if ([[[self sourceViewController] navigationController] respondsToSelector:@selector(showViewController:sender:)]) {

        id sender = nil;
        [[[self sourceViewController] navigationController] showViewController:[self destinationViewController] sender:sender];
    }else{

        [[[self sourceViewController] navigationController] pushViewController:[self destinationViewController] animated:YES];
    }
}

@end

Затем вам нужно установить пользовательский тип для каждого сегмента в вашей раскадровке и выбрать для него новый класс, в моем случае это был MYShowSegue.

Пример настраиваемого перехода

Это решение поможет вам получить полную поддержку ваших приложений iOS 7, они будут использовать метод pushViewController для отправки ваших просмотров, а для iOS 8,9 и т. Д. Ваш переход будет работать с новым (iOS 8) методом showViewController

Не забудьте сделать то же самое со всеми своими сегментами в раскадровке.

Игорь Тихонов
источник
Хорошее решение - у меня сработало (вместо добавления "неиспользуемого" навигационного контроллера ...
Лоренц Глюк
1

Это все еще происходит в iOS 10.x

Удаление и повторная установка сегментов для меня ничего не решило:

Проблема: Требуемая функциональность - это 7 сегментов, которые работают только как «push» (фактически, это деталь шоу), но на самом деле только первый добавленный мной сегмент будет толкать, остальные будут вести себя модально. И это несмотря на то, что Interface Builder идентично описывает каждый из сегментов.

Решение: мне пришлось добавить действие к 6 сегментам, на которых его не было.

Исходная раскадровка в формате XML

<connections>
  <segue destination="tIr-4a-WfZ" kind="showDetail" identifier="A" action="showViewController:sender:" id="8yd-Ne-7KA"/>
  <segue destination="4mB-YE-5dM" kind="showDetail" identifier="B" id="Uod-JC-786"/>
  <segue destination="Qh5-bJ-KcE" kind="showDetail" identifier="C" id="3PW-nV-hWl"/>
  <segue destination="EI6-f4-QBB" kind="showDetail" identifier="D" id="WUK-ju-KDm"/>
  <segue destination="nTz-N4-fpW" kind="showDetail" identifier="E" id="Id6-bW-Huc"/>
  <segue destination="JEp-CH-6dW" kind="showDetail" identifier="F" id="G0L-XW-7f4"/>
  <segue destination="AET-S1-O6h" kind="showDetail" identifier="G" id="3NK-93-wTy"/>
</connections>

Я изменил это, добавив showViewController: sender

<connections>
  <segue destination="tIr-4a-WfZ" kind="showDetail" identifier="A" action="showViewController:sender:" id="8yd-Ne-7KA"/>
  <segue destination="4mB-YE-5dM" kind="showDetail" identifier="B" action="showViewController:sender:" id="Uod-JC-786"/>
  <segue destination="Qh5-bJ-KcE" kind="showDetail" identifier="C" action="showViewController:sender:" id="3PW-nV-hWl"/>
  <segue destination="EI6-f4-QBB" kind="showDetail" identifier="D" action="showViewController:sender:" id="WUK-ju-KDm"/>
  <segue destination="nTz-N4-fpW" kind="showDetail" identifier="E" action="showViewController:sender:" id="Id6-bW-Huc"/>
  <segue destination="JEp-CH-6dW" kind="showDetail" identifier="F" action="showViewController:sender:" id="G0L-XW-7f4"/>
  <segue destination="AET-S1-O6h" kind="showDetail" identifier="G" action="showViewController:sender:" id="3NK-93-wTy"/>
</connections>
Дамо
источник