IOS 8 presentationController определяет, действительно ли это popover
Я использую новую адаптивную возможность "Present As Popover" для iOS 8. Я сделал проводной простой сеанс в StoryBoard, чтобы сделать презентацию. Он отлично работает на iPhone 6 Plus, поскольку он представляет представление как popover и на iPhone 4s, который он показывает как полноэкранный режим (стиль листа).
Проблема заключается в том, что при отображении в виде полноэкранного просмотра мне нужно добавить кнопку "Готово" к представлению, чтобы можно было вызвать функцию отклоненияViewControllerAnimated. И я не хочу показывать кнопку "done", когда она отображается как popover.
![enter image description here]()
Я попробовал посмотреть свойства как presentationController, так и popoverPresentationController, и я не могу найти ничего, что говорит мне, действительно ли оно отображается как popover.
NSLog( @"View loaded %lx", (long)self.presentationController.adaptivePresentationStyle ); // UIModalPresentationFullScreen
NSLog( @"View loaded %lx", (long)self.presentationController.presentationStyle ); // UIModalPresentationPopover
NSLog( @"View loaded %lx", (long)self.popoverPresentationController.adaptivePresentationStyle ); // UIModalPresentationFullScreen
NSLog( @"View loaded %lx", (long)self.popoverPresentationController.presentationStyle ); // UIModalPresentationPopover
adaptivePresentationStyle всегда возвращает UIModalPresentationFullScreen и presentationStyle всегда возвращает UIModalPresentationPopover
Когда я смотрю на UITraitCollection, я нашел признак "_UITraitNameInteractionModel", который был установлен только в 1, когда он фактически отображался как Popover. Тем не менее, Apple не обеспечивает прямой доступ к этому признаку через traitCollection popoverPresentationController.
Ответы
Ответ 1
Лучший способ (наименее вонючий), который я нашел для этого, - использовать UIPopoverPresentationControllerDelegate
.
• Убедитесь, что представленный контроллер представления установлен как UIPopoverPresentationControllerDelegate
на UIPopoverPresentationController
, который используется для управления презентацией. Я использую раскадровку, поэтому установите ее в prepareForSegue:
segue.destinationViewController.popoverPresentationController.delegate = presentedVC;
• Создайте свойство в представленном контроллере просмотра, чтобы отслеживать это состояние:
@property (nonatomic, assign) BOOL amDisplayedInAPopover;
• Добавьте следующий метод делегата (или добавьте к существующему методу делегата):
- (void)prepareForPopoverPresentation:(UIPopoverPresentationController *)popoverPresentationController
{
// This method is only called if we are presented in a popover
self.amDisplayedInAPopover = YES;
}
• И затем, наконец, в viewWillAppear:
- viewDidLoad:
слишком рано, метод подготовки делегата вызывается между viewDidLoad:
и viewWillAppear:
if (self.amDisplayedInAPopover) {
// Hide the offending buttons in whatever manner you do so
self.navigationItem.leftBarButtonItem = nil;
}
Изменить: более простой метод!
Просто установите делегат (убедитесь, что ваш представленный VC принимает UIPopoverPresentationControllerDelegate
):
segue.destinationViewController.popoverPresentationController.delegate = presentedVC;
И поставьте метод:
- (void)prepareForPopoverPresentation:(UIPopoverPresentationController *)popoverPresentationController
{
// This method is only called if we are presented in a popover
// Hide the offending buttons in whatever manner you do so
self.navigationItem.leftBarButtonItem = nil;
}
Ответ 2
Я проверяю, установлено ли popoverPresentationController arrowDirection после отображения представления. Для моих целей это работает достаточно хорошо и охватывает случай popovers на более мелких экранированных устройствах.
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
if (popoverPresentationController?.arrowDirection != UIPopoverArrowDirection.Unknown) {
// This view controller is running in a popover
NSLog("I'm running in a Popover")
}
}
Ответ 3
Я тестировал все решения, представленные в этом сообщении. Извините, никто не работает правильно во всех случаях. Например, в стиле iPad с разделенным изображением стиль представления может меняться при перетаскивании разделенной линии просмотра, поэтому для этого нам нужно специальное уведомление.
После нескольких часов исследований я нашел раствор в образце яблока (быстрый):
https://developer.apple.com/library/ios/samplecode/AdaptivePhotos/Introduction/Intro.html#//apple_ref/doc/uid/TP40014636
Вот то же самое решение в obj-c.
Сначала в функции prepareForSegue задается делегат popoverPresentationController. Он также может быть установлен в MyViewController "init", но не в "viewDidLoad" (потому что сначала будет выдано приглашениеPresentWithAdaptiveStyle перед viewDidLoad).
MyViewController *controller = [segue destinationViewController];
controller.popoverPresentationController.delegate = (MyViewController *)controller;
Теперь объект MyViewController получит это уведомление каждый раз, когда iOS изменяет стиль презентации, включая первое представление. Вот пример реализации, который показывает/скрывает кнопку "Закрыть" в navigationController:
- (void)presentationController:(UIPresentationController *)presentationController
willPresentWithAdaptiveStyle:(UIModalPresentationStyle)style
transitionCoordinator:(nullable id<UIViewControllerTransitionCoordinator>)transitionCoordinator {
if (style == UIModalPresentationNone) {
// style set in storyboard not changed (popover), hide close button
self.topViewController.navigationItem.leftBarButtonItem = nil;
} else {
// style changed by iOS (to fullscreen or page sheet), show close button
UIBarButtonItem *closeButton =
[[UIBarButtonItem alloc] initWithTitle:@"Close" style:UIBarButtonItemStylePlain target:self action:@selector(closeAction)];
self.topViewController.navigationItem.leftBarButtonItem = closeButton;
}
}
- (void)closeAction {
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
}
Ответ 4
UIPresentationController
, который управляет вашим контроллером представления, представляет его, установив modalPresentationStyle
в UIModalPresentationPopover
.
Согласно UIViewController
reference:
presentingViewController
- Контроллер представления, который представил это представление контроллер. (Только для чтения)
modalPresentationStyle
- UIModalPresentationPopover: В горизонтально-обычной среде стиль презентации, в котором содержимое отображается в представлении popover. Фоновый контент затемнен и краны вне popover вызывают отклонение popover. Если ты не хотите, чтобы краны отклонили popover, вы можете назначить один или несколько просмотров свойство passthroughViews ассоциированного Объект UIPopoverPresentationController, который вы можете получить из свойство popoverPresentationController.
Таким образом, мы можем определить, находится ли ваш контроллер просмотра внутри popover или представлен модально, проверив horizontalSizeClass
следующим образом (я предположил, что ваша кнопка UIBarButtonItem
)
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if (self.presentingViewController.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassRegular)
self.navigationItem.leftBarButtonItem = nil; // remove the button
}
Самое безопасное место для проверки - viewWillAppear:
, так как иначе presentingViewController
может быть nil
.
Ответ 5
Как насчет
if (self.modalPresentationStyle == UIModalPresentationPopover)
Он работает для меня
Ответ 6
Официальный способ реализовать это - сначала удалить кнопку "Готово" с вашего контроллера представления, а во-вторых, при адаптации к компактному встраиванию вашего контроллера вида в контроллер навигации, добавив кнопку "Готово" в качестве элемента навигации:
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
return UIModalPresentationStyle.FullScreen
}
func presentationController(controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? {
let navigationController = UINavigationController(rootViewController: controller.presentedViewController)
let btnDone = UIBarButtonItem(title: "Done", style: .Done, target: self, action: "dismiss")
navigationController.topViewController.navigationItem.rightBarButtonItem = btnDone
return navigationController
}
func dismiss() {
self.dismissViewControllerAnimated(true, completion: nil)
}
Полный учебник
![Скриншоты]()
Ответ 7
Решение, которое работает с многозадачей
Назначьте контроллер представления в качестве делегата popover
...
controller.popoverPresentationController.delegate = controller;
[self presentViewController:controller animated:YES completion:nil];
Затем в контроллере реализуем методы делегата:
- (void)presentationController:(UIPresentationController *)presentationController willPresentWithAdaptiveStyle:(UIModalPresentationStyle)style transitionCoordinator:(id<UIViewControllerTransitionCoordinator>)transitionCoordinator
{
if (style != UIModalPresentationNone)
{
// Exited popover mode
self.navigationItem.leftBarButtonItem = button;
}
}
- (void)prepareForPopoverPresentation:(UIPopoverPresentationController *)popoverPresentationController
{
// Entered popover mode
self.navigationItem.leftBarButtonItem = nil;
}
Ответ 8
Мое сложное решение прекрасно работает.
В PopoverViewController
viewDidLoad
.
if (self.view.superview!.bounds != UIScreen.main.bounds) {
print("This is a popover!")
}
Идея проста, размер представления Popover никогда не равен размеру экрана устройства, если это не Popover.