UIActivity activityViewController being presented modally on iPad instead of in popover
Asked Answered
A

4

13

When using a customer UIActivity subclass in iOS 6, it's possible to specify a custom view controller that will be displayed when your action is chosen from the initial UIActionViewController's view. You do this by returning a reference to a custom view controller from your UIActivity subclass's activityViewController method.

According to the UIActivity class reference:

activityViewController

The default implementation of this method returns nil. Subclasses that provide additional UI using a view controller can override this method to return that view controller. If this method returns a valid object, the system presents the returned view controller for you, instead of calling the performActivity method. On iPad, your view controller is presented inside of a popover. On iPhone and iPod touch, your view controller is presented modally.

Your custom view controller should provide a view with your custom UI and should handle any user interactions inside those views. Upon completing the activity, do not dismiss the view controller yourself. Instead, call the activityDidFinish: method and let the system dismiss it for you.

Note that bit at the end of the first paragraph: On iPad, your view controller is presented inside of a popover. On iPhone and iPod touch, your view controller is presented modally.

However, on iPad the view controller returned by activityViewController always displays modally, no matter how I present the UIActivityViewController (either modally or via a popover). When presenting via a popover, it causes it to crash since it doesn't think it's been dismissed.

What am I doing wrong? Is this a bug in iOS 6?


Update: here's a simple Xcode project that illustrates the problem. Feel free to clone it and play around to see if you can see where we're going wrong: github.com/simonwhitaker/GSActivityDemo

Allspice answered 17/11, 2012 at 18:56 Comment(5)
Same problem here. I've amended the original post to add an explicit question, hope you don't mind @Gujamin.Hopkins
too broad, to unspecific .... :( I could start wild guesses but I would rather you edit the question and maybe show some code or such! - oh and are you using arc?Merchant
It seems the same as this openradar.appspot.com/12034514 which would appear to be filed by this SO user (based on the twitter handle too)... stackoverflow.com/users/743524/riley-testut It maybe worth messaging them.Sporting
Did you ever solve this? I'm completely unable to get a custom UIActivity that implements activityViewController to work right on iPad. No problem on iPhone.Aplenty
For what it's worth, this seems to be the simplest solution, but still a bit weird: gist.github.com/mluton/3990658Gumdrop
F
23

As we are talking about the UIActivityViewController, which is the view showing the available activities to the user. Apple state the following...

Your app is responsible for configuring, presenting, and dismissing this view controller. Configuration for the view controller involves specifying the data objects on which the view controller should act. (You can also specify the list of custom services your app supports.) When presenting the view controller, you must do so using the appropriate means for the current device. On iPad, you must present the view controller in a popover. On iPhone and iPod touch, you must present it modally.

I took the last line as a sign that you have to handle how the view is presented, so I check whether the code is running on iPad and use a UIPopover accordingly. As you can sere here... https://github.com/bufferapp/buffer-uiactivity/blob/master/BufferUIActivity/Views/FirstViewController.m within the following method.

-(IBAction)openUIActivityView:(id)sender {

    NSString *text = @"Hello world";
    NSString *url = @"http://bufferapp.com";


    NSArray *activityItems = @[text, url];

    BufferUIActivity *bufferActivity = [[BufferUIActivity alloc] init];

    UIActivityViewController *activityView = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:@[ bufferActivity ]];


    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
        [self presentViewController:activityView animated:YES completion:^{

        }];
    } else {
        // Change Rect to position Popover
        self.popup = [[UIPopoverController alloc] initWithContentViewController:activityView];
        [self.popup presentPopoverFromRect:CGRectMake(self.view.frame.size.width/2, self.view.frame.size.width/2, 100, 100) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
    }

}
Fillender answered 20/11, 2012 at 9:49 Comment(2)
Hi Andy. No, that's not the one we're talking about -- I've clarified the question. We're talking about the custom view controller displayed after the user selects an action. To give a concrete example, I'm adding an "Upload to Dropbox" action to my app. So there's a custom UIActivity subclass that adds a Dropbox button to the activity sheet. When you tap that button I display a custom VC allowing you to choose the destination folder for your files. It's that VC that should display in a popover on iPad, but always displays modally.Hopkins
Apologies, it's an odd one as the UIActivity i've done for Buffer also displays modally on iPad however so does Apple's Twitter/Facebook sheets. I'm inclined to say it's an issue with iOS6 or the documentation is wrong.Fillender
V
3

I think the issue with the activity view controller not showing in a popover is a bug and the docs reflect the correct intent. However, I don’t know of a way to workaround this atm.

The part about dismissing the view controller, however, is a different issue. You are not supposed to dismiss the view controller that you return from -[UIActivity activityViewController], but you are responsible for dismissing the popover that you have presented, which in turn will also remove your custom view controller from the hierarchy. (And because it works this way, I’m inclined to believe that the custom view controller would normally have to be shown in the popover.)

Here’s an example with code from your example app:

UIActivityViewController *vc = [[UIActivityViewController alloc] initWithActivityItems:activityItems
                                                                 applicationActivities:applicationActivities];

vc.completionHandler = ^(NSString *activityType, BOOL completed){
  [self.activityPopoverController dismissPopoverAnimated:YES];
};
Venerable answered 20/11, 2012 at 11:32 Comment(3)
On second thought, like AndyDev mentions, except for the print dialog, all other built-in activities also show with a modal screen. Another clue is that before presenting the custom view controller, it gets the -[UIViewController setModalTransitionStyle:] message, suggesting it really does intentionally want to present it modally.Venerable
Good catch on the issue with the view controller not dismissing. Thanks!Hopkins
I'm guessing there may be a private API call that Apple have neglected to expose, that controls whether to present the activityViewController modally or in the existing popover.Hopkins
B
1


I had the same problem in iOS 7. The solution to show the custom view in the popover is to create and show it in the -(void)performActivity method instead of returning it in -(UIViewController *)activityViewController.

You can see example code in my question/answer under this link:
iOS 7 custom UIActivity as popover

Batangas answered 20/5, 2014 at 9:47 Comment(0)
G
-3

I just had the same problem but solved it by setting the ViewController to:

[yourViewController setModalPresentationStyle:UIModalPresentationPageSheet];

in

- (UIViewController *)activityViewController

hope this helps

Gadgetry answered 16/4, 2013 at 8:32 Comment(1)
The problem is that it's supposed to be presented in a popover on iPad. That does not happen, especially if you force it by setting the presentation style to page sheet.Allspice

© 2022 - 2024 — McMap. All rights reserved.