UIActivity activityViewController being presented modally on iPad instead of in popover

Gujamin picture Gujamin · Nov 17, 2012 · Viewed 18.7k times · Source

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

Answer

AndyDev picture AndyDev · Nov 20, 2012

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];
    }

}