将自定义活动添加到 UIActivityController 的问题

Posted

技术标签:

【中文标题】将自定义活动添加到 UIActivityController 的问题【英文标题】:Problems adding custom activity to UIActivityController 【发布时间】:2012-10-05 18:19:00 【问题描述】:

我正在尝试对标准活动(打印、邮件、FaceBook 等)实施自定义活动,但现在只想要标准打印(用于 AirPrint)和我自己通过直接方法进行的自定义打印。我显然缺少一些基本的东西,因为我的自定义类中的任何方法都没有被调用。目前我只有一些 NSLog 语句来确定调用顺序,并让框架运行。

以下是我对自定义活动类的测试代码:

//  PrintActivity.h

#import <UIKit/UIKit.h>

@interface PrintActivity : UIActivity

@end

还有.m

#import "PrintActivity.h"

@interface PrintActivity ()
@property (nonatomic, strong) UIWebView *dummyWebView;
@end

@implementation PrintActivity

- (NSString *)activityType 
    NSLog(@"activityType");
    return @"MetriScan Print";


- (NSString *)activityTitle 
    NSLog(@"activityTitle");
    return @"MetriScan\nPrint";


- (UIImage *)activityImage 
    NSLog(@"activityImage");
    UIImage *icon = [UIImage imageNamed:@"metriscan_57_c2a_3.png"];
    return icon;


- (BOOL)canPerformWithActivityItems:(NSArray *)activityItems 
    NSLog(@"canPerformWithActivityItems");
    return YES;


- (void)prepareWithActivityItems:(NSArray *)activityItems 
    NSLog(@"prepareWithActivityItems");


- (void)performActivity 
    NSLog(@"Do the actual printing here");
// My custom code here


这是主程序中的调用:

- (IBAction)printReport:(UIBarButtonItem *)sender 
    NSLog(@"Print Report");

    PrintActivity *metriscanPrint = [[PrintActivity alloc] init];

    UIViewPrintFormatter *printFormatter = [self.webView viewPrintFormatter];

    NSArray *activityItems = [NSArray arrayWithObjects:printFormatter, nil];
    NSArray *appActivities = [NSArray arrayWithObjects:metriscanPrint, nil];
    UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:appActivities];
    //activityController.excludedActivityTypes = [NSArray arrayWithObjects:UIActivityTypePostToFacebook, UIActivityTypePostToTwitter, UIActivityTypePostToWeibo, UIActivityTypeMail, UIActivityTypeMessage, nil];
    activityController.completionHandler = ^(NSString *activityType, BOOL completed) 
        sender.enabled = YES;
    ;

    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) 
        [self presentViewController:activityController animated:YES completion:nil];
     else 
        sender.enabled = NO;
        self.printPop = [[UIPopoverController alloc] initWithContentViewController:activityController];
        [self.printPop presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionDown animated:YES];
    

正如我所说,没有调用自定义类中的任何方法,但系统邮件、消息和复制图标显示在活动表中,而不是打印图标。我希望只有系统打印图标(和我自己的)。

如果我取消注释顶部的语句块(并注释掉 NSArray *activityItems ......),则系统邮件、消息、打印和复制图标。在这个实验中,我认为我通过创建自己的格式化程序来混合不同的方法,但这似乎是 WWDC 2012 的建议?

如果我随后取消注释带有“excludeActivityTypes”的行,我只会得到系统打印图标。

我欢迎任何意见来帮助我解决这个问题。

如果有人知道任何示例代码来做我想做的事,那就太好了。

编辑:将代码更新为我的工作代码。

【问题讨论】:

【参考方案1】:

在过去的一周里,我也在 UIActivity 上大发雷霆,Apple 确实需要更好地解释它并添加更多功能;试试这个:

PrintActivity.h

#import <UIKit/UIKit.h>
@interface PrintActivity : UIActivity
@end

PrintActivity.m

#import "PrintActivity.h"

@implementation PrintActivity

- (NSString *)activityType

   return @"MetriScan.Print";


- (NSString *)activityTitle

    return @"Print MtriScan";


- (UIImage *)activityImage
   
    //***** Note: I recommend using two sizes, as the iPad's UIActivity image size differs from 
    //***** the iPhone's. Also, create @2x sizes for Retina compatible devices. So you will     
    //***** have a total of 4 images.
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)

    return [UIImage imageNamed:@"test_72.png"];


    return [UIImage imageNamed:@"test_57.png"];


- (BOOL)canPerformWithActivityItems:(NSArray *)activityItems

    NSLog(@"%s", __FUNCTION__);
    return YES;


- (void)prepareWithActivityItems:(NSArray *)activityItems

    NSLog(@"%s",__FUNCTION__);


- (UIViewController *)activityViewController

    NSLog(@"%s",__FUNCTION__);
    return nil;


- (void)performActivity

    // This is where your custom print code should go



@end

不要忘记同时制作这两个文件:

PrintProvider.h

#import <UIKit/UIKit.h>

@interface PrintProvider : UIActivityItemProvider <UIActivityItemSource>

@end

PrintProvider.m

#import "PrintProvider.h"

@implementation PrintProvider

#pragma mark - UIActivityItemSource

- (id)activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(NSString *)activityType

    NSLog(@"%s",__FUNCTION__);
    NSLog(@"%@", activityType);
    return [super activityViewController:activityViewController itemForActivityType:activityType];


@end  

现在我们终于可以调用它了:

- (IBAction)printReport:(UIBarButtonItem *)sender 


CustomProvider *customProvider =
                [[CustomProvider alloc]init];
                NSArray *items = [NSArray arrayWithObjects:customProvider,nil];

                CustomActivity *ca = [[CustomActivity alloc]init];

                UIActivityViewController *activityVC =
                [[UIActivityViewController alloc] initWithActivityItems:items
                                                  applicationActivities:[NSArray arrayWithObject:ca]];

                activityVC.excludedActivityTypes = @[UIActivityTypePostToWeibo,
                UIActivityTypeAssignToContact,UIActivityTypeCopyToPasteboard,
                UIActivityTypeSaveToCameraRoll,UIActivityTypeMail,UIActivityTypePostToTwitter,
                UIActivityTypePostToFacebook,UIActivityTypeMessage];

                activityVC.completionHandler = ^(NSString *activityType, BOOL completed)
                
                    NSLog(@" activityType: %@", activityType);
                    NSLog(@" completed: %i", completed);
                ;

                    self.popoverController = [[UIPopoverController alloc] initWithContentViewController:activityVC];

                    CGRect rect = [[UIScreen mainScreen] bounds];

                    [self.popoverController
                     presentPopoverFromRect:rect inView:self.view
                     permittedArrowDirections:0
                     animated:YES];

【讨论】:

troop231 感谢您回答问题。事实证明,我几乎和你一样解决了这个问题。我最初的困惑是分别在 activityItems 和 applicationActivities 中放入什么。为了完整起见,我更新了原始问题中的代码。 不客气 :) 我认为 UIActivity 的潜力是巨大的。 谢谢,它确实有效。但是这种方法与 Apple 关于不覆盖系统服务的警告不矛盾吗? You should subclass UIActivity only if you want to provide custom services to the user. The system already provides support for many standard services and makes them available through the UIActivityViewController object. For example, the standard activity view controller supports emailing data, posting items to one of the user’s social media accounts, and several other options. You do not have to provide custom services for any of the built-in types.【参考方案2】:

@troop231 - 很好的答案,非常有帮助。

我唯一要添加的是确保发出操作完成的信号,否则不会调用完成例程并且弹出框不会关闭。比如:

- (void)performActivity 
    NSLog(@"Do the actual activity here");
    // My custom code here

    [self activityDidFinish:YES];  // indicate completion here!!

【讨论】:

感谢您添加此内容。我一直在想正确的方法。这将导致 activityViewController.completionHandler 触发,您应该在此处关闭 avc。 我只是有一个想法,但还没有时间测试它。如果一个(而不是)在返回之前调用[super performActivity],则可能没有必要显式调用完成处理程序(如我上面所示)。超类方法是否有可能调用完成处理程序?如果您有时间尝试,请告诉我。【参考方案3】:

感谢您的帮助,伙计们!而且,对于活动图像,我们似乎必须按照 Apple 文档提供图像:

图像的 alpha 通道用作掩码来生成 呈现给用户的最终图像。图像中的任何颜色数据 本身被忽略。不透明像素应用了渐变,并且 然后将此渐变放置在标准背景之上。因此,一个 完全不透明的图像会产生一个渐变填充的矩形。为了 iPhone 和 iPod touch,图像不应大于 43 x 43 点 (对于配备 Retina 显示屏的设备,这相当于 86 x 86 像素。) 对于 iPad,图像不应大于 55 x 55 点(即 对于配备 Retina 显示屏的 iPad,相当于 110 x 110 像素。)

【讨论】:

以上是关于将自定义活动添加到 UIActivityController 的问题的主要内容,如果未能解决你的问题,请参考以下文章

如何将自定义适配器添加到活动中以使列表出现在活动中?

如何向 SFSafariViewController 添加自定义活动?

有没有办法将自定义数据发送到 Mailchimp 的 API,以便将其包含在活动中?

Android将自定义对象从服务传递给活动

将自定义ListView项目传递给Android中的其他活动

将自定义常量添加到系统常量[重复]