Presenting popover from UIBarButtonItem in iPhone - ios

I want to present a view controller as an popup in iPhone from a UIBarButtonItem
I have written the following piece of code on the action of the button.
-(IBAction)showAvailableCategory:(UIButton *)sender
{
CategoryPopup *categoryPopupViewController = [[CategoryPopup alloc]init];
UIPopoverPresentationController *popOverCat = categoryPopupViewController.popoverPresentationController;
categoryPopupViewController.preferredContentSize = CGSizeMake(138, 122);
popOverCat.delegate = self;
popOverCat.sourceView = sender;
popOverCat.sourceRect = sender.bounds;
popOverCat.permittedArrowDirections = UIPopoverArrowDirectionAny;
[self presentViewController:categoryPopupViewController animated:YES completion:nil];
}
I have made my CategoryPopup as freeform in the xib and also I am implementing the below delegate method
-(UIModalPresentationStyle) adaptivePresentationStyleForPresentationController: (UIPresentationController * ) controller
{
return UIModalPresentationNone;
}
But it does not come up as popup rather it comes fullscreen, is there a workaround?

You forgot just one setting, add it right after categoryPopupViewController's initialization:
categoryPopupViewController.modalPresentationStyle = UIModalPresentationPopover;

Related

UIPopoverPresentationController showing full screen modal popup always

I am trying to show a view controller as UIPopoverPresentationController below the button or in center of window. But it is always showing as full window modal popup.
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
MySecondViewController *controller = [storyboard instantiateViewControllerWithIdentifier:#"Pop"];
// present the controller
// on iPad, this will be a Popover
// on iPhone, this will be an action sheet
controller.modalPresentationStyle = UINavigationControllerOperationPop;
[self presentViewController:controller animated:YES completion:nil];
controller.preferredContentSize = CGSizeMake(280, 230);
// configure the Popover presentation controller
UIPopoverPresentationController *popController = [controller popoverPresentationController];
popController.permittedArrowDirections = UIPopoverArrowDirectionUp;
popController.delegate = self;
// in case we don't have a bar button as reference
popController.sourceView = self.showPop;
popController.sourceRect = CGRectMake(384, -120, 280, 230);
-(UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller {
return UIModalPresentationNone;
}
Try this code it is working
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
SecondViewController *controller = [storyboard instantiateViewControllerWithIdentifier:#"pop"];
controller.modalPresentationStyle = UIModalPresentationPopover;
controller.preferredContentSize = CGSizeMake(280, 230);
// configure the Popover presentation controller
controller.popoverPresentationController.delegate = self;
controller.popoverPresentationController.permittedArrowDirections = UIPopoverArrowDirectionUp;
// in case we don't have a bar button as reference
controller.popoverPresentationController.sourceView = self.view;
controller.popoverPresentationController.sourceRect = CGRectMake(384, -120, 280, 230);
// controller.presentationController.delegate = self;
[self presentViewController:controller animated:YES completion:nil];
I have posted another question for the same question and i have resolved my issue. Here is the link of question:
UIPopoverPresentationController is showing full screen modal on iPhone
In ViewController.h Firstly make a property of UIPopoverPresenatationController.
#property(nonatomic,retain)UIPopoverPresentationController *dateTimePopover8;
Then to show PopOverPresentationcontroller
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.modalPresentationStyle = UIModalPresentationPopover;
destNav.navigationBarHidden = YES;
[self presentViewController:destNav animated:YES completion:nil];
You must have noticed that we are presenting View Controller instead of presenting popOver.So we have to hide this in new way also.It hides automatically when we click on screen.
-(void)hideIOS8PopOver
{
[self dismissViewControllerAnimated:YES completion:nil];
}
We have to implement the delegate of UIPopoverPresenatationController in implementation file.Write below delegate method in implementation file.
- (UIModalPresentationStyle) adaptivePresentationStyleForPresentationController: (UIPresentationController * ) controller {
return UIModalPresentationNone;
}
In Storyboard this is very easy. Just control drag from the control that will trigger the action (say a UIBarButton or a normal button) to the storyboard view controller (if root view of Navigation controller, drag to the navigation controller).
Select the segue and change the Kind in the attribute inspector to "Present Modally", presentation: Form sheet (if you want it to show at the centre), select the transition type you want (default is cool).
As #Lukas1 mentioned above, you should conform UIPopoverPresentationControllerDelegate and implement adaptivePresentationStyle method (which is actually defined in UIAdaptivePresentationControllerDelegate protocol, UIPopoverPresentationControllerDelegate parent class) and return .none
And here's implementation in Swift5 :
extension ViewController: UIPopoverPresentationControllerDelegate {
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return UIModalPresentationStyle.none
}
}

UIPopoverPresentationController is showing full screen modal on iPhone

On iPad UIPopoverPresentationController working fine but on iPhone it is always showing full window modal popup. i am using following code:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
MySecondViewController *contentVC = [storyboard instantiateViewControllerWithIdentifier:#"Pop"];
contentVC.modalPresentationStyle = UINavigationControllerOperationPop; // 13
UIPopoverPresentationController *popPC = contentVC.popoverPresentationController; // 14
contentVC.popoverPresentationController.sourceRect =CGRectMake(100, 130, 280, 230);
self.navigationController.preferredContentSize = CGSizeMake(200, self.parentViewController.childViewControllers.lastObject.preferredContentSize.height-100);
//self.showPop.frame; // 15
contentVC.popoverPresentationController.sourceView =
self.showPop; // 16
popPC.permittedArrowDirections = UIPopoverArrowDirectionAny; // 17
popPC.delegate = self; //18
[self presentViewController:contentVC animated:YES completion:nil];
-(UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller {
return UIModalPresentationNone;
}
In ViewController.h Firstly make a property of UIPopoverPresenatationController.
#property(nonatomic,retain)UIPopoverPresentationController *dateTimePopover8;
Then to show PopOverPresentationcontroller
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.modalPresentationStyle = UIModalPresentationPopover;
destNav.navigationBarHidden = YES;
[self presentViewController:destNav animated:YES completion:nil];
You must have noticed that we are presenting View Controller instead of presenting popOver.So we have to hide this in new way also.It hides automatically when we click on screen.
-(void)hideIOS8PopOver
{
[self dismissViewControllerAnimated:YES completion:nil];
}
We have to implement the delegate of UIPopoverPresenatationController in implementation file.Write below delegate method in implementation file.
- (UIModalPresentationStyle) adaptivePresentationStyleForPresentationController: (UIPresentationController * ) controller {
return UIModalPresentationNone;
}
Popover controllers are for use exclusively on iPad devices.
Edit: As stated by Soberman, since iOS 8 it is possible to present popovers on iPhone using public APIs, so this answer is probably not relevant anymore.
As stated in Apple's documentation on UIPopoverController:
Popover controllers are for use exclusively on iPad devices.
So there is no way to use this class in iPhone application unfortunately. But there are a couple of custom third-party implementations of the functionality provided by UIPopoverController which add iPhone support and more. See https://github.com/50pixels/FPPopover for example.
Edit: There also is another highly customizable popover implementation for both iPhone/iPad worth checking out: https://github.com/nicolaschengdev/WYPopoverController.

How do you programmatically configure and present a popover on iPhone in iOS 8+

How can you present a UIViewController in a popover on iPhone (all sizes and orientations), in iOS 8 using only Objective-C code, no Story Boards or other Interface Builder artifacts.
In iOS 8, you can configure any view controller to be displayed as a popover, like so:
UIViewController* controller = ...; // your initialization goes here
// set modal presentation style to popover on your view controller
// must be done before you reference controller.popoverPresentationController
controller.modalPresentationStyle = UIModalPresentationPopover;
controller.preferredContentSize = CGSizeMake(150, 300);
// configure popover style & delegate
UIPopoverPresentationController *popover = controller.popoverPresentationController;
popover.delegate = controller;
popover.sourceView = sourceView;
popover.sourceRect = CGRectMake(150,300,1,1);
popover.permittedArrowDirections = UIPopoverArrowDirectionAny;
// display the controller in the usual way
[self presentViewController:controller animated:YES completion:nil];
So that it displays as a popover on iPhone, add this to the UIPopoverPresentationControllerDelegate delegate of the popover (that you set above):
- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller
{
return UIModalPresentationNone;
}

iOS 8 Popover controller wont dismiss

I have a trio of functions and a property that I use to control my popovers as follows:
-(void)dismissPopoverIfPresentAnimated:(BOOL)animated
{
if (self.currentPopover)
{
[self.currentPopover dismissPopoverAnimated:animated];
self.currentPopover = nil;
}
}
-(void)presentViewController:(UIViewController *)viewController inView:(UIView *)view fromRect:(CGRect)rect suppressArrow:(BOOL)suppressArrow
{
//Did the user just tap on a button to bring up the same controller that's already displayed?
//If so, just dismiss the current controller.
BOOL closeOnly = NO;
if (self.currentPopover)
{
UIViewController *currentController = [self.currentPopover.contentViewController isKindOfClass:UINavigationController.class] ? ((UINavigationController *)self.currentPopover.contentViewController).topViewController : self.currentPopover.contentViewController;
UIViewController *newController = [viewController isKindOfClass:UINavigationController.class] ? ((UINavigationController *)viewController).topViewController : viewController;
if ([currentController isKindOfClass:newController.class])
closeOnly = YES;
[self dismissPopoverIfPresentAnimated:NO];
}
if (!closeOnly)
{
self.currentPopover = [[UIPopoverController alloc] initWithContentViewController:viewController];
self.currentPopover.backgroundColor = [UIColor whiteColor];
[self.currentPopover presentPopoverFromRect:rect inView:view permittedArrowDirections:(suppressArrow ? 0 : UIPopoverArrowDirectionAny) animated:YES];
}
}
(instancetype) initWithContentViewController:(UIViewController )viewController
{
self = [super initWithContentViewController:[[UIViewController alloc] init]];
if (self)
{
UIViewController contentViewController = super.contentViewController;
[contentViewController addChildViewController:viewController];
[viewController didMoveToParentViewController:contentViewController];
[contentViewController.view addSubview:viewController.view];
[self setPopoverContentSize:viewController.preferredContentSize animated:NO];
}
return self;
}
This runs fine in iOS 7, but in iOS 8 the problem is there is a delay between the call to presentPopoverFromRect and when the item actually shows up onscreen. So, if a user double taps a button to show a popover, the first tap will properly dismiss, then "start" the showing of the new controller. The second tap will make the dismiss call (the popover is not yet visible) and then not show the new controller (this is a design feature so that click a button will show a popover, clicking it again will hide it).
The problem is that the call to dismiss the popover doesn't actually work and the popover will show up. At that point I can't get rid of it because my property is nil and I think it is not showing.
My guess is this is an iOS 8 bug where the dismiss somehow doesn't see a visible popover and thus doesn't do anything, where instead, it should prevent it from showing up.
Oh, one last note is that the call to presentViewController is always done on the main thread.

Present view controller using Storyboards

I have followed a tutorial to add In App Purchases to my app. There are 2 views:
Button to 'Buy item'
Screen comes up that allows user to select product
I have added the code completely fine but in the tutorial they were using XIB files but I am using Storyboard. My code for the 'Buy item' button looks something like this:
- (IBAction)PurchaseItem:(id)sender {
_purchaseController = [[PurchasedViewController alloc] initWithNibName:Nil bundle:nil];
_purchaseController.productID = #"com.myapp";
[self presentViewController:_purchaseController animated:YES completion:NULL];
[_purchaseController getProductID:self];
}
The issue I have is that when the button is clicked, a black screen appears, but I want PurchasedViewController to show
Do I need to change something?
EDIT:
Using edited code but getting error as attached:
- (IBAction)PurchaseItem:(id)sender {
PurchasedViewController *purchaseContr = (PurchasedViewController *)[self.storyboard instantiateViewControllerWithIdentifier:#"menu"];
//menu is only an example
purchaseContr.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:purchaseContr animated:YES completion:nil];
}
With a storyboard you should give an Identifier like in the picture:
tap on your viewController and in 'identity inspector'
in this example Custom Class should be: PurchasedViewController
and this is the code:
- (IBAction)PurchaseItem:(id)sender {
PurchasedViewController *purchaseContr = (PurchasedViewController *)[self.storyboard instantiateViewControllerWithIdentifier:#"menu"];
//menu is only an example
purchaseContr.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:purchaseContr animated:YES completion:nil];
}
Try this
_purchaseController = [[PurchasedViewController alloc] init];
_purchaseController.productID = #"com.myapp";
/* 1. Add the new VC as a child VC */
[self addChildViewController:_purchaseController];
/* 2. Add new view to source view */
[self.view addSubview:_purchaseController.view];
/* 3. Inform 'didMoveToParentViewController' to newly added view controller */
[_purchaseController didMoveToParentViewController:self];
[_purchaseController getProductID:self];

Resources