Как правильно представить всплывающее окно в iOS 8

118

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

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)

}

Я получаю точно такой же результат.

Как мне изменить размер всплывающего окна? Любая помощь будет высоко ценится!

Joris416
источник
На сайте разработчиков есть видео WWDC под названием «Взгляд изнутри контроллеров презентаций». В нем объясняется, как использовать UIPopoverPresentationController
Wextux
Я отредактировал свой вопрос в соответствии с видео Apple, касающимся UIpopoverpresentationctontroller, но ничего не изменилось! ты, может быть, видишь что-нибудь, что я должен изменить по этому поводу? Спасибо за вклад!
Joris416 09

Ответы:

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)

}

Это способ.

Вы больше не разговариваете с самим всплывающим окном, вы разговариваете с контроллером представления внутри него, чтобы установить размер содержимого, вызывая свойство preferredContentSize

Joris416
источник
15
Вероятно, констатирую очевидное, но это связано не только с быстрым. Мне также пришлось сделать это в моем приложении obj-c :)
Kevin R
4
Еще один комментарий к коду - вы можете использовать let вместо var. Apple рекомендует это в случаях, когда вам не нужно переназначать значение.
EPage_Ed
3
Это ошибка GM для iPhone. Если вы попытаетесь представить, когда симулятор находится в портретной ориентации, он всегда будет в полноэкранном режиме. Если повернуть в альбомную ориентацию, оно станет всплывающим. Если вы снова повернетесь к портретной ориентации, она останется всплывающим.
jjxtra
1
Решение состоит в том, чтобы настроить всплывающее окно ПЕРЕД вызовом presentViewController. Это полная противоположность примеру Apple, где они явно говорят вам настроить всплывающее окно ПОСЛЕ вызова presentViewController.
jjxtra
1
@PsychoDad не могли бы вы предоставить ссылку на упомянутое вами решение. Я все еще застрял на «пока симулятор в портретной ориентации, он всегда в полноэкранном режиме». Спасибо
Nishant
53

На самом деле все намного проще. В раскадровке вы должны сделать viewcontroller, который вы хотите использовать как всплывающее окно, и создать для него класс viewcontroller как обычно. Сделайте переход, как показано ниже, из объекта, который вы хотите открыть во всплывающем окне, в данном случае с UIBarButtonименем «Config».

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

В «материнском контроллере представления» реализовать 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
    } 
user1700737
источник
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 02
3
Правильно, UIPopoverPresentationControllerDelegate расширяет UIAdaptivePresentationControllerDelegate. Итак, по определению, оба содержат метод «adaptivePresentationStyleForPresentationController». Я предоставил базовый интерфейс, поскольку именно здесь метод задокументирован в документах Apple API.
Дэвид Хант,
1
Обратите внимание, что это недокументированное поведение. В документе говорится, что этот метод делегата должен возвращать «или UIModalPresentationFullScreenили UIModalPresentationOverFullScreen». Кроме того, «Если вы не реализуете этот метод или не вернете какой-либо стиль, отличный от UIModalPresentationFullScreenили UIModalPresentationOverFullScreen, контроллер представления подстраивает стиль представления к UIModalPresentationFullScreenстилю».
Tom
1
Текущая документация рекомендует, начиная с iOS 8.3, использовать - adaptivePresentationStyleForPresentationController: traitCollection: и этот возвращаемый стиль должен быть «UIModalPresentationFullScreen, UIModalPresentationOverFullScreen, UIModalPresentationFormSheet или UIModalPresentation.
Dale
25

Swift 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 (base: UIView) следует разместить перед ViewDidLoad. Надеюсь, поможет !

AG
источник
привет @Alvin, я собираюсь открыть вид из аннотации карты. так что я сделал то же самое, что и ты. разница в том, что я собираюсь заполнить tableviewcontroller вместо view. Теперь проблема не в методе делегата. "PopoverPresentationControllerDidDismissPopover". когда я увольняю контролера. вы можете помочь ? (вопрос не имеет отношения к посту)
Subin K Kuriakose
1
Почему showPopover(base: UIView)метод следует размещать раньше viewDidLoad()?
Eimantas
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

user2941395
источник
Вопрос конкретно касается Swift, а не Objective-C.
Эрик Айя
4

Лучше всего это объясняется в блоге iOS8 Day-by-Day.

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

Clafou
источник
3

Я сделал Objective-C версию быстрого ответа Imagine Digitals выше. Не думаю, что я что-то пропустил, так как это работает при предварительном тестировании, если вы заметите что-то, дайте мне знать, и я обновлю его

-(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. Вот как я здесь оказался.
narco
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

или: return .pageSheet .... и так далее ..

ingconti
источник
2

Реализуйте UIAdaptivePresentationControllerDelegate в своем Viewcontroller. Затем добавьте :

func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle{
    return .none
}
Nyakiba
источник
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)
}

Надеюсь это поможет.

TheNeil
источник
0

Для желающих учиться!

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

KTListNewResize

tryKuldeepTanwar
источник