Обнаруживать, когда UISplitViewController меняет режим отображения

Я пытаюсь использовать UISplitViewController, где вторичный контроллер должен предоставлять функцию «закрытия» (с помощью кнопки или элемента панели кнопок) всякий раз, когда UISplitViewController находится в параллельном режиме, но должен скрывать функцию в другое время. Я попытался поместить это в контроллер вторичного представления:

override func viewWillAppear(_ animated: Bool) {
    if splitViewController!.primaryHidden {
        // hide the "close" UI artifact
    } else {
        // show the "close" UI artifact
    }
}

Это правильно устанавливает видимость функции «закрыть» при первом отображении вторичного представления, но если UISplitViewController переключается между развернутым и свернутым (скажем, путем поворота iPhone 6s Plus), то эта функция больше не вызывается (что имеет смысл , поскольку вторичный контроллер остается видимым). Следовательно, функция «close» остается в своем исходном состоянии - скрыта или отображается - даже когда UISplitViewController меняет режим.

Как я могу заставить функцию «закрыть» скрыть или показать в ответ на изменения в режиме UISplitViewController?

Можете выложить фото проблемы. Я использую в своем приложении 4 SplitViewController, и они были головной болью, чтобы начать работать. Я постараюсь помочь, если смогу, но мне будет легче разобраться с некоторыми фотографиями проблемы и тем, как вы хотите, чтобы она выглядела

Lance Samaria 05.05.2018 00:23
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
1
1 055
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Хорошо, я нашел простое решение. Я совершал ошибку новичка. Уловка состоит в том, чтобы переопределить viewWillLayoutSubviews() вместо viewWillAppear(animated:). Дальше все работает как хочу. Кажется, что viewWillLayoutSubviews() вызывается (иногда более одного раза) каждый раз, когда содержащий UISplitViewController меняет режим отображения, и это именно то, на что мне нужно ответить. Единственная проблема заключается в том, что splitViewController может быть nil для некоторых из этих вызовов, поэтому его нужно реализовать следующим образом:

override func viewWillAppear(_ animated: Bool) {
    if let svc = splitViewController {
        if svc.primaryHidden {
            // hide the "close" UI artifact
        } else {
            // show the "close" UI artifact
        }
    }
}

Пытаясь найти решение, я попытался переопределить traitCollectionDidChange(previousTraitCollection:). (Я пробовал это, потому что хотел реагировать на поворот устройства.) Сначала я подумал, что наткнулся на что-то, потому что эта функция также вызывается всякий раз, когда устройство вращается. Интересно (и досадно) я обнаружил, что свойство splitViewController моего представления было nil при вызове этой функции. Кажется странным, что это должно быть так, поскольку ни viewDidDisappear(animated:), ни viewWillAppear(animated:) не вызываются, когда UISplitViewController реконфигурирует себя. Но почему это должен быть nil - это, наверное, вопрос другого дня.

Для этого есть уведомление UIViewControllerShowDetailTargetDidChangeNotification:

// Sometimes view controllers that are using showViewController:sender and
// showDetailViewController:sender: will need to know when the split view
// controller environment above it has changed. This notification will be 
// posted when that happens (for example, when a split view controller is
// collapsing or expanding). The NSNotification's object will be the view
// controller that caused the change.
UIKIT_EXTERN NSNotificationName const UIViewControllerShowDetailTargetDidChangeNotification NS_AVAILABLE_IOS(8_0);

Используйте следующим образом

- (void)viewDidLoad{
    [super viewDidLoad];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(showDetailTargetDidChange:) name:UIViewControllerShowDetailTargetDidChangeNotification object:self.splitViewController];
}

- (void)showDetailTargetDidChange:(NSNotification *)notification{
    // changed from collapsed to expanded or vice versa
}

Этот пример Apple демонстрирует, как аксессуар ячейки таблицы изменяется с индикатора раскрытия в портретной ориентации (обозначающего, что произойдет нажатие) на его удаление при переходе в режим разбиения на альбомную ориентацию: https://developer.apple.com/library/archive/samplecode/AdaptivePhotos/Introduction/Intro.html

Обратите внимание на бета-версию iOS 13: используйте addObserver с объектом nil, потому что в настоящее время есть ошибка, когда они отправляют уведомление с использованием неправильного объекта. Они используют свой новый UISplitViewControllerPanelImpl из внутреннего кластера классов вместо объекта UISplitViewController.http://www.openradar.appspot.com/radar?id=4956722791710720

UIViewControllerShowDetailTargetDidChangeNotification никогда не называется. Есть идеи, почему?
RameshVel 04.09.2019 16:35

Если используется бета-версия iOS13, измените addObserver на использование объекта nil. В настоящее время они используют неправильный объект для фильтрации уведомления, но я отправил отзыв, чтобы исправить это.

malhal 04.09.2019 16:37

Спасибо за ответ @malhal. Я вижу эту проблему и в iOS 12.4. Я пробовал передавать как nil, так и splitvc NotificationCenter.default.addObserver(self, selector: #selector(handleSplitVCTransition), name: UIViewController.showDetailTargetDidChangeNotification, object: nil). Но оба никогда не стреляли

RameshVel 04.09.2019 16:55

Попробуйте образец Apple, который я только что добавил к ответу, и проверьте, появляется ли уведомление. Мне нравится использовать симулятор iPhone 8 Plus для тестирования.

malhal 04.09.2019 17:14

Спасибо. Я постараюсь посмотреть

RameshVel 04.09.2019 17:30

Для справки в будущем:

А как насчет использования UISplitViewControllerDelegate ??

У него есть метод, называемый

splitViewController:willChangeToDisplayMode:

это должно делать именно то, что вы ищете.

Документация здесь

Другие вопросы по теме