UIPopoverPresentationController должен иметь ненулевой sourceView или barButtonItem, установленный до того, как презентация произойдет в iOS 9.

Я пытаюсь показать всплывающее окно, используя собственный класс UIPopoverPresentationController. Но он вылетает с ошибкой(<UIPopoverPresentationController: 0x7a772950>) should have a non-nil sourceView or barButtonItem set before the presentation occurs. Ниже приведен мой код нажатия кнопки, где происходит сбой.

- (IBAction)showPopup:(UIButton *)sender {
ViewController *contentViewController = [[ViewController alloc] init];

    contentViewController.preferredContentSize = CGSizeMake(200, 200);
    contentViewController.modalPresentationStyle = UIModalPresentationPopover;
    myPopoverController *popOver = [[myPopoverController alloc]initWithPresentedViewController:contentViewController presentingViewController:self andTintColor:[UIColor lightGrayColor]];

    popOver.delegate = self;
    popOver.permittedArrowDirections = UIPopoverArrowDirectionUp;
    popOver.sourceRect = sender.frame;
    popOver.sourceView = self.view;
    [self presentViewController:contentViewController animated: YES completion: nil];
}

Ниже приведен пример того, как выглядит мой собственный UIPopoverPresentationController.

myPopoverController.h file

@interface myPopoverController : UIPopoverPresentationController

@property (readonly) UIColor *tintColor;


-(instancetype)initWithPresentedViewController:(UIViewController *)presentedViewController presentingViewController:(UIViewController *)presentingViewController andTintColor:(UIColor *)aTintColor;

@end


myPopoverController.m file

//Some code for UIPopoverBackgroundView

-(instancetype)initWithPresentedViewController:(UIViewController *)presentedViewController presentingViewController:(UIViewController *)presentingViewController
{

    self = [self initWithPresentedViewController:presentedViewController presentingViewController:presentingViewController andTintColor: [UIColor redColor]];

    return self;
}


-(instancetype)initWithPresentedViewController:(UIViewController *)presentedViewController presentingViewController:(UIViewController *)presentingViewController andTintColor:(UIColor *)aTintColor
{

    self = [super initWithPresentedViewController:presentedViewController presentingViewController:presentingViewController];

    if (!self) {
        return nil;
    }

    [super setPopoverBackgroundViewClass: [myPopoverControllerBackgroundView class]];
    tintColor = aTintColor;


    return self;
}

У меня нет кнопки, но я устанавливаю sourceView. Я делаю что-то не так здесь? Ценю вашу помощь


person Francis F    schedule 21.03.2017    source источник


Ответы (5)


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

- (IBAction)showPopup:(UIButton *)sender {

ViewController *contentViewController = [[ViewController alloc] init];
    contentViewController.preferredContentSize = CGSizeMake(200, 200);
    contentViewController.modalPresentationStyle = UIModalPresentationPopover;

UIPopoverPresentationController *popoverpresentationController = contentViewController.popoverPresentationController;
    popoverpresentationController.delegate = self;
    popoverpresentationController.permittedArrowDirections = UIPopoverArrowDirectionUp;
    popoverpresentationController.sourceRect = sender.bounds;
    popoverpresentationController.sourceView = sender;
    [self presentViewController:contentViewController animated: YES completion: nil];
}
person Martin    schedule 07.04.2017

Вы создаете подкласс UIPopoverPresentationController, но Apple рекомендует использовать их такими, какие они есть. После того, как вы представите UIViewController, будет автоматически создан UIPopoverPresentationController, и вы должны изменить его для своих нужд.

Вы создаете экземпляр myPopoverController, но Apple создает еще один, когда вы present contentViewController сразу после:

[self presentViewController:contentViewController animated: YES completion: nil];

В этом новом UIPopoverPresentationController отсутствует sourceView и возникает исключение.

Вместо этого попробуйте код ниже:

ViewController *contentViewController = [[ViewController alloc] init];

// Present the view controller using the popover style.
contentViewController.modalPresentationStyle = UIModalPresentationPopover;
[self presentViewController:contentViewController 
                   animated:YES 
                 completion:nil];

// Get the popover presentation controller and configure it.
UIPopoverPresentationController *presentationController =[contentViewController popoverPresentationController];
presentationController.permittedArrowDirections = UIPopoverArrowDirectionUp;
presentationController.sourceView = self.view;
presentationController.sourceRect = sender.frame;
person Yunus Nedim Mehel    schedule 27.07.2017
comment
Вы инвертировали назначения sourceView и sourceRect в последних двух строках вашего образца. - person Martin-Gilles Lavoie; 05.09.2019

Если sourceView имеет значение null, просто добавьте проверку

UIActivityViewController * avc = [[UIActivityViewController alloc] initWithActivityItems:shareItems applicationActivities:nil];
if(avc.popoverPresentationController){
    avc.popoverPresentationController.sourceView = self.view;
}
[self presentViewController:avc animated:YES completion:nil];

Посмотреть этот пост

person Erick Dávila    schedule 03.02.2021
comment
Это сработало для меня. Я столкнулся со сбоем только на iPad (а не на iPhone или iPod Touch). На самом деле мне пришлось заменить .sourceView на .barButtonItem и установить его равным элементу кнопки панели, который я добавил к своему navigationController.navigationItem. - person Chris Allinson; 06.03.2021

Может быть ниже код может помочь:

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

  1. barButtonItem
  2. sourceView
  3. sourceRect

Сделайте следующее:

//for iPhone
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {

    [self presentViewController:controller animated:YES completion:nil];

}
//for iPad
else {
    // Change Rect as required
    ViewController *contentViewController = [[ViewController alloc] init];

    contentViewController.preferredContentSize = CGSizeMake(200, 200);
    contentViewController.modalPresentationStyle = UIModalPresentationPopover;
    [self presentViewController:contentViewController animated:YES completion:nil];
}
person Ronak Chaniyara    schedule 21.03.2017
comment
UIPopoverController устарел, начиная с iOS 9. - person Francis F; 21.03.2017

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

extension XXXBaseViewController: UIPopoverPresentationControllerDelegate {

    override func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil) {
        if let popController = viewControllerToPresent.popoverPresentationController,
            popController.sourceView == nil{
            return
        }
        super.present(viewControllerToPresent, animated: flag, completion: completion)
    }
}
person kkklc    schedule 16.05.2019
comment
Однажды я столкнулся с ситуацией. Если памяти недостаточно, она будет автоматически восстановлена. - person kkklc; 04.06.2020