Як правильно представити popover в iOS 8


118

Я намагаюся додати UIPopoverView до свого додатку Swift iOS 8, але мені не вдається отримати доступ до властивості PopoverContentSize, оскільки popover не відображається у правильній формі. мій код:

var popover: UIPopoverController? = nil 

    func addCategory() {

    var newCategory = storyboard.instantiateViewControllerWithIdentifier("NewCategory") as UIViewController
    var nav = UINavigationController(rootViewController: newCategory)
    popover = UIPopoverController(contentViewController: nav)
    popover!.setPopoverContentSize(CGSizeMake(550, 600), animated: true)
    popover!.delegate = self
    popover!.presentPopoverFromBarButtonItem(self.navigationItem.rightBarButtonItem, permittedArrowDirections: UIPopoverArrowDirection.Any, animated: true)
}

вихід:

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

Коли я роблю те саме, що виконуються через UIPopoverPresentationController, я все одно не закінчую це. це мій код:

func addCategory() {

    var popoverContent = self.storyboard.instantiateViewControllerWithIdentifier("NewCategory") as UIViewController
    var nav = UINavigationController(rootViewController: popoverContent)
    nav.modalPresentationStyle = UIModalPresentationStyle.Popover
    var popover = nav.popoverPresentationController as UIPopoverPresentationController
    popover.delegate = self
    popover.popoverContentSize = CGSizeMake(1000, 300)
    popover.sourceView = self.view
    popover.sourceRect = CGRectMake(100,100,0,0)

    self.presentViewController(nav, animated: true, completion: nil)

}

Я отримую точно такий же вихід.

Як налаштувати розмір мого поїзда? Будь-яка допомога буде дуже вдячна!


На веб-сайті розробника є відео WWDC під назвою "Погляньте всередину презентаційних контролерів", де пояснюється, як користуватися UIPopoverPresentationController
Wextux

Я відредагував своє запитання відповідно до відео з яблуком щодо UIpopoverpresentationctontroller, але нічого не змінилося! Ви, можливо, можете щось змінити з цього приводу? Дякую за вклад, хоча!
Joris416

Відповіді:


148

Гаразд, домогосподарка поглянула на це і зрозуміла:

 func addCategory() {

    var popoverContent = self.storyboard?.instantiateViewControllerWithIdentifier("NewCategory") as UIViewController
    var nav = UINavigationController(rootViewController: popoverContent)
    nav.modalPresentationStyle = UIModalPresentationStyle.Popover
    var popover = nav.popoverPresentationController
    popoverContent.preferredContentSize = CGSizeMake(500,600)
    popover.delegate = self
    popover.sourceView = self.view
    popover.sourceRect = CGRectMake(100,100,0,0)

    self.presentViewController(nav, animated: true, completion: nil)

}

Ось так.

Ви більше не спілкуєтесь із самим Popover, ви розмовляєте з контролером перегляду всередині нього, щоб встановити розмір вмісту, зателефонувавши до ресурсу preferredContentSize


15
Ймовірно, констатуючи очевидне, але це не просто швидко. Я також повинен був зробити це у своєму додатку obj-c :)
Kevin R

4
Ще один коментар до коду - ви можете використовувати "хай" замість "var". Apple рекомендує його у випадках, коли вам не потрібно перепризначати значення.
EPage_Ed

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

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

1
@PsychoDad Ви можете, будь ласка, надати посилання на це рішення, згадане у вас. Я все ще застряг у "поки тренажер стоїть у портреті, він завжди на повному екрані". Спасибі
Нішант

53

Насправді це набагато простіше цього. У дошці розкадрування вам слід зробити контролер перегляду, який ви хочете використовувати як перехожий, і зробити клас перегляду контролерів для нього, як зазвичай. Зробіть знімок, як показано нижче, від об'єкта, на який потрібно відкрити поповер, у цьому випадку з UIBarButtonназвою "Налаштувати".

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

У "материнському контролері перегляду" реалізуйте UIPopoverPresentationControllerDelegateметод і делегат:

func popoverPresentationControllerDidDismissPopover(popoverPresentationController: UIPopoverPresentationController) {
    //do som stuff from the popover
}

Замініть такий prepareForSequeметод:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
     //segue for the popover configuration window
    if segue.identifier == "yourSegueIdentifierForPopOver" {
        if let controller = segue.destinationViewController as? UIViewController {
            controller.popoverPresentationController!.delegate = self
            controller.preferredContentSize = CGSize(width: 320, height: 186)
        }
    }
}

І ви закінчили. І тепер ви можете ставитися до перегляду попу, як до будь-якого іншого погляду, тобто. додайте поля, а що ні! І ви отримаєте контролер вмісту за допомогою popoverPresentationController.presentedViewControllerметоду вUIPopoverPresentationController .

Також на iPhone вам доведеться перезаписати

func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {

        return UIModalPresentationStyle.none
    } 

28

Я знайшов повний приклад того, як змусити це все працювати так, що ви завжди зможете відобразити попову, незалежно від пристрою / орієнтації https://github.com/frogcjn/AdaptivePopover_iOS8_Swift .

Ключовим моментом є реалізація UIAdaptivePresentationControllerDelegate

func adaptivePresentationStyleForPresentationController(PC: UIPresentationController!) -> UIModalPresentationStyle {
    // This *forces* a popover to be displayed on the iPhone
    return .None
}

Потім розгорніть приклад вище (від Imagine Digital):

nav.popoverPresentationController!.delegate = implOfUIAPCDelegate

Я використовую UIPopoverPresentationControllerDelegate
onmyway133

3
Правильно, UIPopoverPresentationControllerDelegate розширює UIAdaptivePresentationControllerDelegate. Отже, за визначенням, обидва містять метод 'adaptivePresentationStyleForPresentationController'. Я надав базовий інтерфейс, оскільки саме цей метод задокументований в документах API Apple.
Девід Хант

1
Зауважте, це недокументована поведінка. Док каже, що цей метод делегата повинен повернути " UIModalPresentationFullScreenабо UIModalPresentationOverFullScreen". Крім того, "Якщо ви не реалізуєте цей метод або не повертаєте будь-який стиль, відмінний від UIModalPresentationFullScreenабо UIModalPresentationOverFullScreen, контролер презентації адаптує стиль презентації до UIModalPresentationFullScreenстилю."
Том

1
Поточна документація передбачає, що з iOS 8.3 ви повинні використовувати - adaptivePresentationStyleForPresentationController: traitCollection: і повернутий стиль повинен бути "UIModalPresentationFullScreen, UIModalPresentationOverFullScreen, UIModalPresentationFormSheet, orUseNPPP", "UIModalPresentationFormSheet", or.
Дейл

25

Швидкий 2.0

Ну я відпрацював. Подивитися. Зробив ViewController в StoryBoard. Пов’язаний з класом PopOverViewController.

import UIKit

class PopOverViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()    
        self.preferredContentSize = CGSizeMake(200, 200)    
        self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Done, target: self, action: "dismiss:")    
    }    
    func dismiss(sender: AnyObject) {
        self.dismissViewControllerAnimated(true, completion: nil)
    }
}      

Див. ViewController:

//  ViewController.swift

import UIKit

class ViewController: UIViewController, UIPopoverPresentationControllerDelegate
{
    func showPopover(base: UIView)
    {
        if let viewController = self.storyboard?.instantiateViewControllerWithIdentifier("popover") as? PopOverViewController {    

            let navController = UINavigationController(rootViewController: viewController)
            navController.modalPresentationStyle = .Popover

            if let pctrl = navController.popoverPresentationController {
                pctrl.delegate = self

                pctrl.sourceView = base
                pctrl.sourceRect = base.bounds

                self.presentViewController(navController, animated: true, completion: nil)
            }
        }
    }    
    override func viewDidLoad(){
        super.viewDidLoad()
    }    
    @IBAction func onShow(sender: UIButton)
    {
        self.showPopover(sender)
    }    
    func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
        return .None
    }
}  

Примітка: Метод func showPopover (база: UIView) слід розмістити перед ViewDidLoad. Сподіваюся, це допомагає!


привіт @Alvin, я збираюся спливати подання з анотації на карті. тому я зробив те саме, що і ти. Різниця полягає в тому, що я збираюсь заповнити tableviewcontroller замість view. Тепер проблема полягає не в натисканні методу делегата. "PopoverPresentationControllerDidDismissPopover". коли я звільняю контролер. Ви можете допомогти ? (питання не пов’язане з посадою)
Subin K Kuriakose

1
Чому showPopover(base: UIView)метод слід розміщувати раніше viewDidLoad()?
Еймантас

15

У iOS9 UIPopoverController амортизується. Отже, можна використовувати код нижче для версії Objective-C над iOS9.x,

- (IBAction)onclickPopover:(id)sender {
UIStoryboard *sb = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
UIViewController *viewController = [sb instantiateViewControllerWithIdentifier:@"popover"];

viewController.modalPresentationStyle = UIModalPresentationPopover;
viewController.popoverPresentationController.sourceView = self.popOverBtn;
viewController.popoverPresentationController.sourceRect = self.popOverBtn.bounds;
viewController.popoverPresentationController.permittedArrowDirections = UIPopoverArrowDirectionAny;
[self presentViewController:viewController animated:YES completion:nil]; }

Питання спеціально задає Swift, а не Objective-C.
Ерік Айя

8

Ось я перетворять код Swift "Joris416" в Objective-c,

-(void) popoverstart
{
    ViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:@"PopoverView"];
    UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:controller];
    nav.modalPresentationStyle = UIModalPresentationPopover;
    UIPopoverPresentationController *popover = nav.popoverPresentationController;
    controller.preferredContentSize = CGSizeMake(300, 200);
    popover.delegate = self;
    popover.sourceView = self.view;
    popover.sourceRect = CGRectMake(100, 100, 0, 0);
    popover.permittedArrowDirections = UIPopoverArrowDirectionAny;
    [self presentViewController:nav animated:YES completion:nil];
}

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

Не забудьте додати
UIPopoverPresentationControllerDelegate, UIAdaptivePresentationControllerDelegate


Питання спеціально задає Swift, а не Objective-C.
Ерік Айя

4

Це найкраще пояснюється у щоденному блозі iOS8

Коротше кажучи, як тільки ви встановите для свого модуля UIViewController модульPresentationStyle значення .Popover, ви можете отримати власність UIPopoverPresentationClass (новий клас iOS8) через властивість popoverPresentationController контролера.


3

Я зробив швидку відповідь «Imagine Digitals» від Objective-C вище. Я не думаю, що я нічого не пропустив, оскільки, здається, працює під попереднім тестуванням, якщо ви помітите щось, повідомте мене, і я оновлю це

-(void) presentPopover
{
    YourViewController* popoverContent = [[YourViewController alloc] init]; //this will be a subclass of UIViewController
    UINavigationController* nav =  [[UINavigationController alloc] initWithRootViewController:popoverContent];
    nav.modalPresentationStyle = UIModalPresentationPopover;
    UIPopoverPresentationController* popover = nav.popoverPresentationController;
    popoverContent.preferredContentSize = CGSizeMake(500,600);
    popover.delegate = self;
    popover.sourceRect = CGRectMake(100,100,0,0); //I actually used popover.barButtonItem = self.myBarButton;

    [self presentViewController:nav animated:YES completion:nil];
}

Я думаю, що ти popover.sourceView = self.view;
пройшов

Питання спеціально задає Swift, а не Objective-C.
Ерік Айя

4
Я усвідомлюю це, але Google приводить вас сюди, навіть якщо ви шукаєте об'єктив-C. Ось так я і опинився тут.
нарко

3

мої два центи для xcode 9.1 / swift 4.

class ViewController: UIViewController, UIPopoverPresentationControllerDelegate {

    override func viewDidLoad(){
        super.viewDidLoad()

        let when = DispatchTime.now() + 0.5

        DispatchQueue.main.asyncAfter(deadline: when, execute: { () -> Void in
            // to test after 05.secs... :)
            self.showPopover(base: self.view)

        })

}


func showPopover(base: UIView) {
    if let viewController = self.storyboard?.instantiateViewController(withIdentifier: "popover") as? PopOverViewController {

        let navController = UINavigationController(rootViewController: viewController)
        navController.modalPresentationStyle = .popover

        if let pctrl = navController.popoverPresentationController {
            pctrl.delegate = self

            pctrl.sourceView = base
            pctrl.sourceRect = base.bounds

            self.present(navController, animated: true, completion: nil)
        }
    }
}


@IBAction func onShow(sender: UIButton){
    self.showPopover(base: sender)
}

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

та експериментуйте у:

func adaptivePresentationStyle ...

    return .popover

або: повернення .pageSheet .... і так далі ..


2

Реалізуйте UIAdaptivePresentationControllerDelegate у своєму Viewcontroller. Потім додайте:

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

1

Далі наведено досить вичерпне керівництво про те, як налаштувати та представити перехожі. https://www.appcoda.com/presentation-controllers-tutorial/

Підсумовуючи це, життєздатна реалізація (з деякими оновленнями з оригінального синтаксису статті для Swift 4.2 ), яку потім слід викликати з іншого місця, буде щось на зразок наступного:

func showPopover(ofViewController popoverViewController: UIViewController, originView: UIView) {
    popoverViewController.modalPresentationStyle = UIModalPresentationStyle.popover
    if let popoverController = popoverViewController.popoverPresentationController {
        popoverController.delegate = self
        popoverController.sourceView = originView
        popoverController.sourceRect = originView.bounds
        popoverController.permittedArrowDirections = UIPopoverArrowDirection.any
    }
    self.present(popoverViewController, animated: true)
}

Багато цього було вже висвітлено у відповіді від @mmc, але стаття допомагає пояснити деякі з цих елементів коду, а також показати, як його можна розширити.

Він також надає багато додаткових деталей щодо використання делегації для обробки стилю презентації для iPhone проти iPad, а також дозволяє звільнення попу, якщо він коли-небудь буде показаний на весь екран. Знову оновлено для Swift 4.2 :

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

func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
    if traitCollection.horizontalSizeClass == .compact {
        return UIModalPresentationStyle.none
        //return UIModalPresentationStyle.fullScreen
    }
    //return UIModalPresentationStyle.fullScreen
    return UIModalPresentationStyle.none
}

func presentationController(_ controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? {
    switch style {
    case .fullScreen:
        let navigationController = UINavigationController(rootViewController: controller.presentedViewController)
        let doneButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.done, target: self, action: #selector(doneWithPopover))
        navigationController.topViewController?.navigationItem.rightBarButtonItem = doneButton
        return navigationController
    default:
        return controller.presentedViewController
    }
}

// As of Swift 4, functions used in selectors must be declared as @objc
@objc private func doneWithPopover() {
    self.dismiss(animated: true, completion: nil)
}

Сподіваюся, це допомагає.


0

Для тих, хто хоче вчитися!

Я створив проект із відкритим кодом для тих, хто хоче вивчити та використовувати перегляд Popover для будь-яких цілей. Ви можете знайти проект тут. https://github.com/tryWabbit/KTListPopup

KTListNewResize

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.