UIPopoverController for iphone not working?
Asked Answered
D

8

40

I need to use a UIPopOverController for my iPhone app ,i searched stackoverflow someone said UIPopoverController does not run on iphone iphone device WHY?.when i run on iphone device i got this error reason: '-[UIPopoverController initWithContentViewController:] called when not running under UIUserInterfaceIdiomPad.'

 -(void)btnSetRemainderTapped:(UIButton *)button
{
   setReminderView =[[SetRemainderView alloc]initWithNibName:@"SetRemainderView" bundle:[NSBundle mainBundle]];
setReminderView.contentSizeForViewInPopover = CGSizeMake(setReminderView.view.frame.size.width, setReminderView.view.frame.size.height);
setReminderView.delegate = self;
popOverController = [[UIPopoverController alloc]
                      initWithContentViewController:setReminderView] ;
 CGRect rect = CGRectMake(self.view.frame.size.width/2, self.view.frame.size.height/2, 1, 1);
[popOverController presentPopoverFromRect:rect
                                        inView:self.view
                      permittedArrowDirections:UIPopoverArrowDirectionAny
                                      animated:YES];
}

can any one help me?

Diversification answered 9/2, 2013 at 11:45 Comment(0)
S
44

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.

Spermous answered 9/2, 2013 at 14:16 Comment(1)
This answer, since iOS8, is no longer true. Check out my answer to see how to do it natively on iPhone, using the same popover class for iPhone as for iPad.Modie
S
65

You CAN use popoverController in iPhone apps.

1. Create a category

// UIPopoverController+iPhone.h file
@interface UIPopoverController (iPhone)
+ (BOOL)_popoversDisabled;
@end

// UIPopoverController+iPhone.m file
@implementation UIPopoverController (iPhone)
+ (BOOL)_popoversDisabled {
    return NO; 
} 
@end

2. Import it to your class and use popover in iPhone as usual.

But remember that this is private method and Apple can reject your app. But I know people who use this normally and Apple published their apps.

Stutman answered 15/2, 2013 at 13:12 Comment(22)
could you post sample project uipopoverController for iphone without using third party classDiversification
i downloaded your sample popoverController in iPhone apps working fine .i have doubt in your sample project.Why you imported UIPopoverController+iPhone.h class in ViewController.mDiversification
This is not a class. This is category. Well to use a category you need to import itStutman
My application with this solution in app store!Stutman
HI Philip, can you please provide URL of your app using this solution? Thanks!Dewain
Couldn't agree more. Awesome, and a simple way to get around yet more of Apple's dumbness. They DO know it's 2014, don't they..?Chasidychasing
great solution, it helped me as well as possibleDys
Does anyone know the equivalent of this for Xamarin?Argyll
I've uploaded similar demo project to GitHub (in the case you can't access "file download" sites) github.com/abacomm/UIPopoverController-HackJarman
You really better use swizzling to avoid static checks from Apple.Micra
This solution work fine on my iOS device but, on the simulator it freezes the app. Anyone else with the same problem?Implacable
I am using this method, any confirmation if Apple has started to block it? If yes, I will convert to You really better use swizzling to avoid static checks from Apple. – Andy Jun 30 at 18:40 - otherwise, why bother :)Precritical
@NikolayDS, My app got accepted two weeks ago using this method. So No!Implacable
Does anybody have a link to an iPhone app in the store that uses this?Allo
@QED, nice try, Apple.Alonzoaloof
Looks like this solution was disabled by Apple in iOS 8. In my case the app doesn't crash, but popover behaves just as modal view controller.Anitaanitra
@PhilipJ.Fry Thanks it is working fine in iOS7 but what is the work around for iOS8 ?Deuterium
@Anitaanitra did you find any solution for iOS8? if yes please share! Thanks in advanceDeuterium
@Deuterium I utilised WYPopoverController class (written by Nicolas CHENG).Anitaanitra
This example does not work for me. The popup takes the whole screen. Anybody has the same problem?Passade
Simply it works ^^. Thanks very much, as my app is no need to be submitted to Appstore.Chaim
this one not working while using it with Uiimagepickecontroller and in landscape mode...Kealey
S
44

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.

Spermous answered 9/2, 2013 at 14:16 Comment(1)
This answer, since iOS8, is no longer true. Check out my answer to see how to do it natively on iPhone, using the same popover class for iPhone as for iPad.Modie
M
30

Since iOS8 we are now able to create popovers, that will be the same on iPhone, as on iPad, which would be especially awesome for those who make universal apps, thus no need to make separate views or code.

You can get the class as well as demo project here: https://github.com/soberman/ARSPopover

All you need to do is subclass UIViewController, conform to the UIPopoverPresentationControllerDelegate protocol and set desired modalPresentationStyle along with the delegate value:

// This is your CustomPopoverController.m

@interface CustomPopoverController () <UIPopoverPresentationControllerDelegate>

@end

@implementation CustomPopoverController.m

- (instancetype)init {
    if (self = [super init]) {
        self.modalPresentationStyle = UIModalPresentationPopover;
        self.popoverPresentationController.delegate = self;
    }
    return self;
}

- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller {
    return UIModalPresentationNone; //You have to specify this particular value in order to make it work on iPhone.
}

Afterwards, instantiate your newly created subclass in the method from which you want to show it and assign two more values to sourceView and sourceRect. It looks like this:

CustomPopoverController *popoverController = [[CustomPopoverController alloc] init];
popoverController.popoverPresentationController.sourceView = sourceView; //The view containing the anchor rectangle for the popover.
popoverController.popoverPresentationController.sourceRect = CGRectMake(384, 40, 0, 0); //The rectangle in the specified view in which to anchor the popover.
[self presentViewController:popoverController animated:YES completion:nil];

And there you have it, nice, neat blurred popover.

Modie answered 23/5, 2015 at 22:32 Comment(11)
I'm trying out your code, it is indeed showing a popover. I'm just struggling with setting the correct size for the popover. If I use your code to show the popover, the screen gets blurred, but I don't see my popover (because you set the coördinates, but width and height to 0, I suppose). If I do set a size for the sourceRect, the popover is about the same size of the screen, regardless of what size I'm using. Am I doing something wrong?Foraminifer
View controllers have a writeable preferredContentSize property that you can use to specify how much space the content will take up. Inside viewDidLoad pass your CGRect in preferredContentSize and you should be fine.Modie
I have assembled a demo project, here, take a look: github.com/soberman/ARSPopoverModie
crash on iOS7 with message Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[ARSPopover popoverPresentationController]: unrecognized selector sent to instance 0x1649a820Ingamar
I have clearly stated, that this works starting from iOS8.Modie
ok but i have to use in both iOS can u have any other solution?Ingamar
No. You will have to draw one or use already created ones from links in this thread.Modie
@Modie How would I approach to modify ARSPopover to house a tableview? For ARSPopover, should I inherit from UITableViewController instead, and insert a tableview? Asking for your opinion. Thanks.Westbrooks
@Ippier There are no problems just embedding your UITableView into the popover itself with method insertContentIntoPopover. You could create your own model, that is going to be as a delegate and dataSource for this table view. It could look like this: [popoverController insertContentIntoPopover:^(ARSPopover *popover) { UITableView *tableView = [[UITableView alloc] initWithFrame:popover.view.frame style:UITableViewStylePlain]; tableView.delegate = <#your class here#>; tableView.dataSource = <#your class here#>; [popover.view addSubview:tableView]; }];Modie
@Ippier Just install my class with Cocoapods and you should find that method there. In case you want to implement it yourself - no need to change the superclass to UITableViewController, just assign your delegate and dataSource delegate to another class, in order to keep the popover itself more reusable.Modie
@Modie Ok thanks.. a bit late when I saw this. I made it inherit from UITableViewController and implemented the tableviewcontroller delegates as I was used to. Your method should work as well, thanks!Westbrooks
L
14

So @Sobermans answer didn't really solve the issue from start to finish for me so I want to detail how I got it done using the docs. That being said I do like the idea of using your own presentation controller subclass to manage all of the customisation you want to exhibit.

1. Create your controller to present

The first step is instantiating the controller you want to present:

let vc: UIViewController = ...
vc.modalPresentationStyle = .Popover
vc.preferredContentSize = CGSize(width: CGRectGetWidth(view.bounds)/2, height: 100)

Now we have a controller with the popover presentation style and an arbitrary content size.

2. Implement adaptivePresentationStyleForPresentationController

By default UIPopoverPresentationController will present on full screen on iPhone so to prevent this behaviour you need to force the adaptive presentation style to none.

First we set the delegate of the popover presentation controller

vc.popoverPresentationController.delegate = self;

Then we implement UIPopoverPresentationControllerDelegate

func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
    return .None;
}

3. Present and configure popup

First we need to call presentViewController and only after that can we configure the popover:

presentViewController(vc, animated:true, completion:nil)
if let popover = vc.popoverPresentationController {
    popover.permittedArrowDirections = .Right | .Left
    popover.sourceView = button
    popover.sourceRect = button.bounds
}
Loutitia answered 8/9, 2015 at 8:4 Comment(3)
I`m doing this the way you explained in objective c. But at: [self presentViewController:_popoverVC animated:true completion:nil]; my App will chrash, any idea?Fructificative
@Fructificative what's the reason for the crash?Loutitia
I have ask a new question on StackoverflowFructificative
B
3

Use a custom popover controller, such as:

https://github.com/sammcewan/WYPopoverController

(this seems to be the best supported one that I have found).

Befriend answered 18/9, 2014 at 0:2 Comment(0)
A
1

I ended up creating my custom tooltip/popover class.

Can be initalised with any content view and dynamically adjusts it's frame.

Hope it helps.

https://github.com/akeara/AKETooltip

Asexual answered 8/2, 2015 at 11:0 Comment(0)
S
0

If you want to do it in Swift, I believe the code is the following:

extension UIPopoverController {
    class var _popoversDisabled : Bool {
    get { return false }
    }
}

Edit: It is working in Xcode 6 beta 4 on iPhone with iOs7.1

Salangi answered 31/7, 2014 at 13:39 Comment(0)
C
0

This is a really interesting (and depressing) thread to read. I can't believe Apple prevents popup dialogs on iPhones, with absolutely no justification.

And, it's true, on iOS 8, if you try to work around this limitation, it'll make your popups appear as a full-screen modal dialog.

The following excellent webpage describes "How Apple Cheats" to let its own iBooks and iTunes apps break its own rules, and allow popups - but just from within their own iPhone apps.

HowAppleCheats

Have a read (warning: it'll make you hate Apple & XCode even more..)

Want to get around the "UIPopoverController called when not running under UIUserInterfaceIdiomPad" error on iOS 8 ?

Simple.

Just go into your .plist file, and change the Bundle ID to "com.apple.itunesu" to make XCode think that your app is actually iTunes.

Then your popup will work fine.

enter image description here

(Sigh.)

The alternative way of doing this is to directly add your UIViewController to your screen.

Popup

In this example, I wanted a "helper screen" to appear on top of my iPhone screen. It's a UIViewController, it is stored in it's own .xib file, and it has a few lines to add a pretty border:

- (void)viewDidLoad {
    [super viewDidLoad];
    // Give our popup a pretty curved border
    self.view.layer.borderColor = [[UIColor blueColor] CGColor];
    self.view.layer.borderWidth = 1.0;
    self.view.layer.cornerRadius = 8;    
}

To display it, I simply create an instance of this UIViewController, add it to my screen, then center it:

-(void)showHelperScreen
{
    if (self.helperScreen == nil)
    {
        //  Add the popup UIViewController to our screen
        self.helperScreen = [[HelperViewController alloc] init];
        [self.view addSubview:self.helperScreen.view];
    }

    //  Center the popup in the middle of the screen
    CGSize screenSize = [[UIScreen mainScreen] applicationFrame].size;
    self.helperScreen.view.center = CGPointMake(screenSize.width/2, screenSize.height/2);
}

Of course, I also needed to add some code to make the popup disappear when the user taps outside of it, but this does at least show that you can (safely) display popups on an iPhone, even if your app isn't specifically called iTunes or iBook.

Voila.

Hope this helps, and if anyone needs me, I'll be back in my safe, happy place (Visual Studio, in other words).

Chasidychasing answered 5/2, 2015 at 10:35 Comment(1)
Changing your bundle identifier to the iTunes bundle identifier will make it so that you can't upload your app to the app store, won't it?Elisabetta

© 2022 - 2024 — McMap. All rights reserved.