问题
I'm trying to show a popup using a custom UIPopoverPresentationController class. But it crashes with the error(<UIPopoverPresentationController: 0x7a772950>) should have a non-nil sourceView or barButtonItem set before the presentation occurs.
Below is my button click code where the crash 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];
}
Below is a sample of how my custom UIPopoverPresentationController looks like
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;
}
I don't have a barbutton but I'm setting the sourceView. Am I doing something wrong here? Appreciate your help
回答1:
You can create a popover presentation controller like this also and it may work
- (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];
}
回答2:
You are subclassing the UIPopoverPresentationController
but Apple recommends to use them as they are. Once you present a UIViewController
, a UIPopoverPresentationController
will be automatically created and you are supposed to modify it for your needs.
You create an myPopoverController
instance but Apple creates another when you present
your contentViewController
right after:
[self presentViewController:contentViewController animated: YES completion: nil];
This new UIPopoverPresentationController
lacks the sourceView
and throws an exception.
Try the code below instead:
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 = sender.frame;
presentationController.sourceRect = self.view;
回答3:
May be below code could help:
In iPad
the view controller will be displayed as a popover using the new UIPopoverPresentationController
, it requires to specify an anchor point for the presentation of the popover using one of the three following properties:
barButtonItem
sourceView
sourceRect
Do as follows:
//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];
}
回答4:
The Best way I think is override present method
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)
}
}
来源:https://stackoverflow.com/questions/42920340/uipopoverpresentationcontroller-should-have-a-non-nil-sourceview-or-barbuttonite