UIPopoverPresentationController на iOS 8 iPhone


75

Хтось знає, чи UIPopoverPresentationControllerможна використовувати їх для презентації поповер на iPhone? Цікаво, чи додала Apple цю функцію на iOS 8, намагаючись створити уніфіковані контролери презентацій для iPad та iPhone.

Не впевнений, чи нормально запитувати / відповідати на запитання від бета-версії. У такому випадку я його видалю.

Відповіді:


84

Ви можете замінити адаптивну поведінку за замовчуванням ( UIModalPresentationFullScreenу компактному горизонтальному середовищі, тобто iPhone), використовуючи adaptivePresentationStyleForPresentationController:метод, доступний через UIPopoverPresentationController.delegate.

UIPresentationControllerвикористовує цей метод, щоб попросити використовувати новий стиль презентації, який у вашому випадку просто повернення UIModalPresentationNoneпризведе до того, UIPopoverPresentationControllerщо візуалізація відображатиметься як поповер, а не на весь екран.

Ось приклад використання поповеру з використанням налаштування segue в раскадровці від a UIBarButtonItemдо " представити модально " aUIViewController

class SomeViewController: UIViewController, UIPopoverPresentationControllerDelegate {

    // override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) { // swift < 3.0
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "PopoverSegue" {
            if let controller = segue.destinationViewController as? UIViewController {
                controller.popoverPresentationController.delegate = self
                controller.preferredContentSize = CGSize(width: 320, height: 186)                
            }
        }
    }

    // MARK: UIPopoverPresentationControllerDelegate

    //func adaptivePresentationStyleForPresentationController(controller: UIPresentationController!) -> UIModalPresentationStyle { // swift < 3.0
    func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
        // Return no adaptive presentation style, use default presentation behaviour
        return .None
    }
}

Цей фокус було згадано у сесії 214 WWDC 2014 "Перегляд контролера в iOS8" (36:30)


2
Це виправлено в GM для iPhone. Якщо ви намагаєтеся презентувати, поки тренажер знаходиться в портретному режимі, він завжди є на весь екран. Якщо повернути в альбомному режимі, це стає popover. Якщо ви знову повернетеся до портрета, він залишатиметься вправною.
jjxtra

17
Рішення полягає в тому, щоб налаштувати popover ДО виклику presentViewController. Це якраз протилежне прикладу Apple, де вони явно кажуть вам налаштувати покажчик ПІСЛЯ виклику presentViewController.
jjxtra

4
Той самий фрагмент коду в obj-c для тих, хто не вміє читати Swift: stackoverflow.com/a/28143620/1228075
Армін

@PsychoDad має рацію. Моє почуття логіки та довіри просто руйнувалось. Нікому не довіряйте, навіть відео WWDC та посиланням на клас Apple.
Даніель

@Daniel Справді. Встановити його перед поданням все одно має набагато більше сенсу, і цілком можливо, Apple змінила це до виходу релізу.
jjxtra 03.03.15

75

Якщо хтось хоче представити поповер лише кодом, ви можете скористатися наступним підходом.

МЕТА - С

Заявити про властивість UIPopoverPresentationController:

@property(nonatomic,retain)UIPopoverPresentationController *dateTimePopover8;

Використовуйте наступний метод, щоб представити вікно від UIButton:

- (IBAction)btnSelectDatePressed:(id)sender
{
    UINavigationController *destNav = [[UINavigationController alloc] initWithRootViewController:dateVC];/*Here dateVC is controller you want to show in popover*/
    dateVC.preferredContentSize = CGSizeMake(280,200);
    destNav.modalPresentationStyle = UIModalPresentationPopover;
    _dateTimePopover8 = destNav.popoverPresentationController;
    _dateTimePopover8.delegate = self;
    _dateTimePopover8.sourceView = self.view;
    _dateTimePopover8.sourceRect = sender.frame;
    destNav.navigationBarHidden = YES;
    [self presentViewController:destNav animated:YES completion:nil];
}

Використовуйте такий метод, щоб представити вікно від UIBarButtonItem:

- (IBAction)btnSelectDatePressed:(id)sender
{
    UINavigationController *destNav = [[UINavigationController alloc] initWithRootViewController:dateVC];/*Here dateVC is controller you want to show in popover*/
    dateVC.preferredContentSize = CGSizeMake(280,200);
    destNav.modalPresentationStyle = UIModalPresentationPopover;
    _dateTimePopover8 = destNav.popoverPresentationController;
    _dateTimePopover8.delegate = self;
    _dateTimePopover8.sourceView = self.view;
     CGRect frame = [[sender valueForKey:@"view"] frame];
    frame.origin.y = frame.origin.y+20;
    _dateTimePopover8.sourceRect = frame;
    destNav.navigationBarHidden = YES;
    [self presentViewController:destNav animated:YES completion:nil];
}

Реалізуйте цей метод делегатів також у своєму контролері перегляду:

- (UIModalPresentationStyle) adaptivePresentationStyleForPresentationController: (UIPresentationController * ) controller {
    return UIModalPresentationNone;
}

Щоб відхилити цю програму, просто відхиліть контролер подання. Нижче наведено код для відхилення контролера перегляду:

-(void)hideIOS8PopOver
{
    [self dismissViewControllerAnimated:YES completion:nil];
}

SWIFT

Використовуйте наступний метод для представлення вікна від UIButon:

func filterBooks(sender: UIButon)
    {
        let filterVC =  FilterDistanceViewController(nibName: "FilterDistanceViewController", bundle: nil)
        var filterDistanceViewController = UINavigationController(rootViewController: filterVC)
        filterDistanceViewController.preferredContentSize = CGSizeMake(300, 205)
        let popoverPresentationViewController = filterDistanceViewController.popoverPresentationController
        popoverPresentationViewController?.permittedArrowDirections = .Any
        popoverPresentationViewController?.delegate = self
        popoverPresentationController?.barButtonItem = self.navigationItem.rightBarButtonItem
        popoverPresentationViewController!.sourceView = self.view;
        popoverPresentationViewController!.sourceRect = sender.frame

        filterDistanceViewController.modalPresentationStyle = UIModalPresentationStyle.Popover
        filterDistanceViewController.navigationBarHidden = true
        self.presentViewController(filterDistanceViewController, animated: true, completion: nil)
    }

Використовуйте такий метод, щоб представити вікно від UIBarButtonItem:

func filterBooks(sender: UIBarButtonItem)
    {
        let filterVC =  FilterDistanceViewController(nibName: "FilterDistanceViewController", bundle: nil)
        var filterDistanceViewController = UINavigationController(rootViewController: filterVC)
        filterDistanceViewController.preferredContentSize = CGSizeMake(300, 205)
        let popoverPresentationViewController = filterDistanceViewController.popoverPresentationController
        popoverPresentationViewController?.permittedArrowDirections = .Any
        popoverPresentationViewController?.delegate = self
        popoverPresentationController?.barButtonItem = self.navigationItem.rightBarButtonItem
        popoverPresentationViewController!.sourceView = self.view;
        var frame:CGRect = sender.valueForKey("view")!.frame
        frame.origin.y = frame.origin.y+20
        popoverPresentationViewController!.sourceRect = frame

        filterDistanceViewController.modalPresentationStyle = UIModalPresentationStyle.Popover
        filterDistanceViewController.navigationBarHidden = true
        self.presentViewController(filterDistanceViewController, animated: true, completion: nil)
    }

Реалізуйте цей метод делегатів також у своєму контролері перегляду:

func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle{
        return .None
    }

Будь ласка, не забудьте додати делегата UIPopoverPresentationControllerDelegateу файл .h / .m / .swift


Це добре працювало для мене на iPhone в альбомному режимі iOS8 / Swift
листоріз

1
Я не думаю, що UIPopoverPresentationController потрібно декларувати. Це спрацювало для мене, коли я просто отримую доступ до нього та встановлюю його властивість через контролер перегляду призначення. Я використовую Swift та Xcode 6.2.
Даніель

1
destNav.popoverPresentationController - нуль.
Бен Аффлек,

Якщо у вас виникла ця проблема, допоможіть іншим людям, перейшовши до документації, де Apple неправильно описує, як налаштувати покажчик, і натисніть кнопку зворотного зв'язку та запропонуйте їм виправити перелік кодів.
hwaxxer

1
Не працює в моєму випадку: dateVC ініціалізується без Розкадровки
Loc

11

ПРОБЛЕМА: iPhone popover відображає повноекранний режим і не поважає значення preferContentSize.

РІШЕННЯ: На відміну від того, що Apple пропонує у посиланні на клас UIPopoverPresentationController, представлення контролера подання після отримання посилання на контролер презентації popover та його налаштування.

// Get the popover presentation controller and configure it.
//...

// Present the view controller using the popover style.
[self presentViewController:myPopoverViewController animated: YES completion: nil]; 

те саме тут, реалізація делегата і всього було недостатньо, презентація після налаштування зробила фокус на iPhone 6S iOS 10.1
dvkch

важливо лише встановити делегата перед presentViewController,
BugaBuga

3

Переконайтеся, що реалізовано UIAdaptivePresentationControllerDelegate

подобається це:

- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller {
    return UIModalPresentationNone;
}

Якщо ви не хочете повноекранних вікон


2

Я знайшов кілька обхідних шляхів.

На Xcode6.1 використовуйте presentationController.delegateзамість popoverPresentationController.delegate.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier compare:@"showPopOver"] == NSOrderedSame) {
        UINavigationController * nvc = segue.destinationViewController;
        UIPresentationController * pc = nvc.presentationController;
        pc.delegate = self;
    }
}

#pragma mark == UIPopoverPresentationControllerDelegate ==
- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller
{
    return UIModalPresentationNone;
}

У WWDC 2014 "Перегляд досягнень контролера в iOS8" нижче наведені коди можуть відображати вікно на iPhone.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{

    UINavigationController * nvc = segue.destinationViewController;
    UIPopoverPresentationController * pvc = nvc.popoverPresentationController;
    pvc.delegate = self;
}

#pragma mark == UIPopoverPresentationControllerDelegate ==
- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller
{
    return UIModalPresentationNone;
}

Але на Xcode 6.1 у цих кодах відображається презентація FullScreen ... (nvc.popoverPresentationController не має значення)

Я сумніваюся, що це може бути помилка Apple.


1

У iOS 8.3 та пізніших версіях використовуйте наступний синтаксис у UIPopoverPresentationControllerDelegateпротоколі, щоб замінити спливаючі вікна UIModalPresentationStyle.

func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
    return .none
}

0

додайте ці два методи у свій клас WEBVIEW. і додати

-(void) prepareForSegue: (UIStoryboardSegue * ) segue sender: (id) sender {
    // Assuming you've hooked this all up in a Storyboard with a popover presentation style
    if ([segue.identifier isEqualToString: @"showPopover"]) {
        UINavigationController * destNav = segue.destinationViewController;
        pop = destNav.viewControllers.firstObject;
        // This is the important part
        UIPopoverPresentationController * popPC = destNav.popoverPresentationController;
        popPC.delegate = self;
    }
}

- (UIModalPresentationStyle) adaptivePresentationStyleForPresentationController: (UIPresentationController * ) controller {
    return UIModalPresentationNone;
}

0

Ви можете розширити UIPopoverPresentationControllerDelegate так:

protocol PopoverPresentationSourceView {}
extension UIBarButtonItem : PopoverPresentationSourceView {}
extension UIView : PopoverPresentationSourceView {}

extension UIPopoverPresentationControllerDelegate where Self : UIViewController {
   func present(popover: UIViewController, 
        from sourceView: PopoverPresentationSourceView, 
        size: CGSize, arrowDirection: UIPopoverArrowDirection) {

      popover.modalPresentationStyle = .popover
      popover.preferredContentSize = size
      let popoverController = popover.popoverPresentationController
      popoverController?.delegate = self
      if let aView = sourceView as? UIView {
          popoverController?.sourceView = aView
          popoverController?.sourceRect = CGRect(x: aView.bounds.midX, y: aView.bounds.midY, width: 0, height: 0)
      } else if let barButtonItem = sourceView as? UIBarButtonItem {
          popoverController?.barButtonItem = barButtonItem
      }
      popoverController?.permittedArrowDirections = arrowDirection
      present(popover, animated: true, completion: nil)
   }
}

Тепер ви можете телефонувати present(popover: from: size: arrowDirection: )з будь-якого контролера перегляду, який реалізує, UIPopoverPresentationControllerDelegateнаприклад.

class YourViewController : UIViewController {
    @IBAction func someButtonPressed(_ sender: UIButton) {
        let popover = SomeViewController()
        present(popover: popover, from: sender, size: CGSize(width: 280, height: 400), arrowDirection: .right)
    }
}

extension YourViewController : UIPopoverPresentationControllerDelegate {
    func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
        return .none
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.