研究 UIActivityViewController

发布于:2014-04-25 09:51阅读数:5903

特定的编程语言,如 Lisp、lo 和 Mathematica 都是同像性的(homoiconic),意味着它们的代码可作为数据原语呈现,也就是说它们自身就可在代码中被操纵。许多其他语言,包括 Objective-C ,就不同了

“”

 
阅读器

本文由@nixzhu翻译至nshipster的《UIActivityViewController
数据与代码的关系一直都让人好奇。
 
特定的编程语言,如 Lisplo和 Mathematica 都是同像性的(homoiconic),意味着它们的代码可作为数据原语呈现,也就是说它们自身就可在代码中被操纵。许多其他语言,包括 Objective-C ,就不同了,在两者之间建立了严格的界限,回避 eval() 和其它潜在的危险的动态指示加载方法。
 
当问题中的数据过大或难以表示为除了字节流之外的任何东西时,那么代码与数据的这种紧张关系就达到了一个新的高度。关于“如何编码、解码以及解释图像、文档和媒体的二进制表示”的问题从最开始的操作系统开始就一直存在着。
 
OS X 的 Core Services 框架与 iOS 的移动 Core Services 框架都提供函数通过通用类型标识符(Universal Type Identifiers,即UTI)来根据文件扩展和MIME类型识别和分类数据类型。UTI提供了可扩展和可继承的分类系统,它能给予开发人员极大的灵活性,即使是处理最奇特的文件类型。例如,一个 Ruby 源代码文件(.rb)被分类为 Ruby 源代码 > 源代码 > 文本 > 内容 > 数据;一个 QuickTime 电影文件(.mov)被分类为视频 > 电影 > 试听内容 > 内容 > 数据;
 
在桌面文件系统抽象里,UTI工作得相当好。然而,在一个移动范式里,文件和目录对于用户来说都被隐藏了,于是这很快就失效了。而且,更重要的是,云服务和社交媒体的兴起已经让远程实体比本地文件具有更重要的地位。因此,UTI和URL之间出现了紧张关系。
 
很明显我们需要其它的某种东西。那 UIActivityViewController 能成为我们拼命追求的解决办法吗?
 
UIActivityViewController ,出现于 iOS 6,在应用里为分享和操作数据提供了一个统一的服务接口。
 
给出一个可操作数据的集合,那一个 UIActivityViewController 实例就可如下创建:
  1. NSString *string = ...;
  2. NSURL *URL = ...;
  3. UIActivityViewController *activityViewController =
  4. [[UIActivityViewController alloc] initWithActivityItems:@[string, URL]
  5. applicationActivities:nil];
  6. [navigationController presentViewController:activityViewController
  7. animated:YES
  8. completion:^{
  9. // ...
  10. }];
 
这将在屏幕的底部呈现如下所示的东西: 
 
默认情况下,UIActivityViewController 将显示所有可用于所提供内容的服务,但我们也可以排除特定的 Activity 类型。
  1. activityViewController.excludedActivityTypes = @[UIActivityTypePostToFacebook];
 
Activity 类型又分为“操作”和“分享”两大类:
UIActivityCategoryAction
1. UIActivityTypePrint
2. UIActivityTypeCopyToPasteboard
3. UIActivityTypeAssignToContact
4. UIActivityTypeSaveToCameraRoll
5. UIActivityTypeAddToReadingList
6. UIActivityTypeAirDrop
 
UIActivityCategoryShare
1. UIActivityTypeMessage
2. UIActivityTypeMail
3. UIActivityTypePostToFacebook
4. UIActivityTypePostToTwitter
5. UIActivityTypePostToFlickr
6. UIActivityTypePostToVimeo
7. UIActivityTypePostToTencentWeibo
8. UIActivityTypePostToWeibo
 
每个 Activity 类型都支持好多种不同的数据类型。例如,一条 Tweet 可能由 NSString 以及一个附加的图像 和/或 URL 所组成。
 
不同的 Activity 类型所支持的数据类型 
 
<UIActivityItemSource> & UIActivityProvider
类似于一个剪贴板条目只在必要时才提供数据,为了避免过多的内存分配或处理时间, Activity 条目可以是自定义类型。
 
<UIActivityItemSource>
获取数据项
1. activityViewControllerPlaceholderItem:
2. activityViewController:itemForActivityType:
 
提供数据项信息
1. activityViewController:subjectForActivityType:
2. activityViewController:dataTypeIdentifierForActivityType:
3. activityViewController:thumbnailImageForActivityType:suggestedSize:
 
一个关于这些方法如何使用的例子是自定义一个消息,其根据是否要分享到 Facebook 或 Twitter 分别定义。
  1. - (id)activityViewController:(UIActivityViewController *)activityViewController
  2. itemForActivityType:(NSString *)activityType
  3. {
  4. if ([activityType isEqualToString:UIActivityTypePostToFacebook]) {
  5. return NSLocalizedString(@"Like this!");
  6. } else if ([activityType isEqualToString:UIActivityTypePostToTwitter]) {
  7. return NSLocalizedString(@"Retweet this!");
  8. } else {
  9. return nil;
  10. }
  11. }
 
创建一个自定义 UIActivity
除了上述系统提供的 Activity ,你也可以自己创建 Activity。
 
作为例子,让我们创建一个自定义 Activity 类型,它能接受一个图片 URL 并使用 mustache.me 为其安上一瞥胡子。 
之前
之后
 
首先,我们为 Activity 类型定义一个反向DNS标识符(reverse-DNS identifier),指定类别为 UIActivityCategoryAction ,然后提供一个本地化的标题和一个合适于iOS版本的图像:
  1. static NSString * const HIPMustachifyActivityType = @"com.nshipster.activity.Mustachify";
  2. #pragma mark - UIActivity
  3. + (UIActivityCategory)activityCategory {
  4. return UIActivityCategoryAction;
  5. }
  6. - (NSString *)activityType {
  7. return HIPMustachifyActivityType;
  8. }
  9. - (NSString *)activityTitle {
  10. return NSLocalizedString(@"Mustachify", nil);
  11. }
  12. - (UIImage *)activityImage {
  13. if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_6_1) {
  14. return [UIImage imageNamed:@"MustachifyUIActivity7"];
  15. } else {
  16. return [UIImage imageNamed:@"MustachifyUIActivity"];
  17. }
  18. }
 
接下来,我们创建一个帮助函数,HIPMatchingURLsInActivityItems,它返回一个由任何所支持类型的图像 URL 组成的数组。
  1. static NSArray * HIPMatchingURLsInActivityItems(NSArray *activityItems) {
  2. return [activityItems filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:
  3. ^BOOL(id item, __unused NSDictionary *bindings) {
  4. if ([item isKindOfClass:[NSURL class]] &&
  5. ![(NSURL *)item isFileURL]) {
  6. return [[(NSURL *)item pathExtension] caseInsensitiveCompare:@"jpg"] == NSOrderedSame ||
  7. [[(NSURL *)item pathExtension] caseInsensitiveCompare:@"png"] == NSOrderedSame;
  8. }
  9. return NO;
  10. }]];
  11. }
 
这个函数用于 -canPerformWithActivityItems: 和 prepareWithActivityItems: 以取得第一个 PNG 或 JPEG 的加了胡子的图像 URL,如果有的话。
  1. - (BOOL)canPerformWithActivityItems:(NSArray *)activityItems {
  2. return [HIPMatchingURLsInActivityItems(activityItems) count] > 0;
  3. }
  4. - (void)prepareWithActivityItems:(NSArray *)activityItems {
  5. static NSString * const HIPMustachifyMeURLFormatString = @"http://mustachify.me/%d?src=%@";
  6. self.imageURL = [NSURL URLWithString:[NSString stringWithFormat:HIPMustachifyMeURLFormatString, self.mustacheType, [HIPMatchingURLsInActivityItems(activityItems) firstObject]]];
  7. }
 
我们的网络服务提供了好几种胡子选项,它们定义在一个 NS_ENUM 中:
  1. typedef NS_ENUM(NSInteger, HIPMustacheType) {
  2. HIPMustacheTypeEnglish,
  3. HIPMustacheTypeHorseshoe,
  4. HIPMustacheTypeImperial,
  5. HIPMustacheTypeChevron,
  6. HIPMustacheTypeNatural,
  7. HIPMustacheTypeHandlebar,
  8. };
 
最终,我们提供一个 UIViewController 来显示图像。在这个例子里,一个简单的 UIWebView 控制器就够了。 
  1. @interface HIPMustachifyWebViewController : UIViewController <UIWebViewDelegate>
  2. @property (readonly, nonatomic, strong) UIWebView *webView;
  3. @end
  4. - (UIViewController *)activityViewController {
  5. HIPMustachifyWebViewController *webViewController = [[HIPMustachifyWebViewController alloc] init];
  6. NSURLRequest *request = [NSURLRequest requestWithURL:self.imageURL];
  7. [webViewController.webView loadRequest:request];
  8. return webViewController;
  9. }
 
要使用我们全新的胡子 Activity,我们简单地将其传递给一个 UIActivityViewController 的初始化函数即可:
  1. HIPMustachifyActivity *mustacheActivity = [[HIPMustachifyActivity alloc] init];
  2. UIActivityViewController *activityViewController =
  3. [[UIActivityViewController alloc] initWithActivityItems:@[imageURL]
  4. applicationActivities:@[mustacheActivity];
 
手动调用操作
现在正是回忆起 “UIActivityViewController 允许用户执行它们选择的操作” 的好时机,但当情况需要时,分享依然可以手动调用。
 
为了完整性,下面就来介绍手动执行这些操作的步骤: 
打开 URL
  1. NSURL *URL = [NSURL URLWithString:@"http://nshipster.com"];
  2. [[UIApplication sharedApplication] openURL:URL];
系统支持的 URL scheme 包括:mailto://、tel://、sms://、and maps://。
 
添加到 Safari 阅读列表
  1. @import SafariServices;
  2. NSURL *URL = [NSURL URLWithString:@"http://nshipster.com/uiactivityviewcontroller"];
  3. [[SSReadingList defaultReadingList] addReadingListItemWithURL:URL
  4. title:@"NSHipster"
  5. previewText:@"..."
  6. error:nil];
 
保存到相册
  1. UIImage *image = ...;
  2. id completionTarget = self;
  3. SEL completionSelector = @selector(didWriteToSavedPhotosAlbum);
  4. void *contextInfo = NULL;
  5. UIImageWriteToSavedPhotosAlbum(image, completionTarget, completionSelector, contextInfo);
 
发送短信
  1. @import MessageUI;
  2. MFMessageComposeViewController *messageComposeViewController = [[MFMessageComposeViewController alloc] init];
  3. messageComposeViewController.delegate = self;
  4. messageComposeViewController.recipients = @[@"mattt@nshipster•com"];
  5. messageComposeViewController.body = @"Lorem ipsum dolor sit amet";
  6. [navigationController presentViewController:messageComposeViewController animated:YES completion:^{
  7. // ...
  8. }];
 
发送邮件
  1. @import MessageUI;
  2. MFMailComposeViewController *mailComposeViewController = [[MFMailComposeViewController alloc] init];
  3. [mailComposeViewController setToRecipients:@[@"mattt@nshipster•com"]];
  4. [mailComposeViewController setSubject:@"Hello"];
  5. [mailComposeViewController setMessageBody:@"Lorem ipsum dolor sit amet"
  6. isHTML:NO];
  7. [navigationController presentViewController:mailComposeViewController animated:YES completion:^{
  8. // ...
  9. }];
 
发送推文
  1. @import Twitter;
  2. TWTweetComposeViewController *tweetComposeViewController =
  3. [[TWTweetComposeViewController alloc] init];
  4. [tweetComposeViewController setInitialText:@"Lorem ipsum dolor sit amet."];
  5. [self.navigationController presentViewController:tweetComposeViewController
  6. animated:YES
  7. completion:^{
  8. //...
  9. }];
 
IntentKit
虽然所有这些都让人影响深刻也很有用,但在与 Android 上的丰富的 Intent 模型对比之下,iOS 的 Activity 范式中还是有一些特殊的缺失。
 
在 Android 上,应用可以注册不同的 Intent,以表面它们可用于地图或作为浏览器,而且能被选择为相关 Activity 的默认应用,例如导航或将某个URL加入书签。
 
虽然 iOS 缺少可扩展的基础架构来支持这些,但一个第三方的库,叫做 IntentKit,由 @lazerwalker (有着f*ingblocksyntax.com 的声誉) 编写,它是一个有趣的关于我们如何缩小差距的例子。 
 
正常情况下,在一开始一个开发者就要做许多工作,例如查询某个特定的应用是否已被安装,以及构造一个 URL 以支持某个特定的 Activity 等。
 
IntentKit 合并了连接到这些最流行的服务(如 Web、地图、邮件、Twitter、Facebook以及Google+这些客户端)的逻辑,而且它的 UI 非常类似 UIActivityViewController。
 
任何想将其应用的分享体验提高一个层次的人都应该研究一下它。
 
还有一个要发出的有力争论是,关于 iOS 平台的长期生存能力取决于如 UIActivityViewController 这样的分享机制。俗话说,“信息需要自由”。而任何阻挡人民联盟的事物终将输给那些不阻挡联盟的事物。
 
公开的 远程视图控制器(remote view controller) API 的未来前景给了我关于iOS上分享的未来希望。虽然对现在来说,我们当然可以做得比 UIActivityViewController 更差。(译者注:是这个意思吗? For now, though, we could certainly do much worse than UIActivityViewController.) 

CocoaChina是全球最大的苹果开发中文社区,官方微信每日定时推送各种精彩的研发教程资源和工具,介绍app推广营销经验,最新企业招聘和外包信息,以及Cocos2d引擎、Cocostudio开发工具包的最新动态及培训信息。关注微信可以第一时间了解最新产品和服务动态,微信在手,天下我有!
 
请搜索微信号“CocoaChina”关注我们!
 

研究 UIActivityViewController的更多相关文章

  1. iOS-微信分享多张图片(UIActivityViewController多图分享和多图分享失败)

    前言 微信分享到朋友圈,可分享的类型有:文字类型.图片类型.音乐类型.视频类型和网页类型,但是我们在做图片分享的时候发现微信给的API只能分享一张图片,达不到一些APP的需求,而产品汪或者Boss想要 ...

  2. IOS6 新特性之UIActivityViewController详解

    新的IOS6增加了一些新特性.因为应用需要,所以在国庆的几天里.研究了一下IOS6的说明文档,然后大概地总结了一下UIActivityViewController的用法与大家分享. 首先 从实际效果入 ...

  3. 闲来无聊,研究一下Web服务器 的源程序

    web服务器是如何工作的 1989年的夏天,蒂姆.博纳斯-李开发了世界上第一个web服务器和web客户机.这个浏览器程序是一个简单的电话号码查询软件.最初的web服务器程序就是一个利用浏览器和web服 ...

  4. SQLSERVER聚集索引与非聚集索引的再次研究(上)

    SQLSERVER聚集索引与非聚集索引的再次研究(上) 上篇主要说聚集索引 下篇的地址:SQLSERVER聚集索引与非聚集索引的再次研究(下) 由于本人还是SQLSERVER菜鸟一枚,加上一些实验的逻 ...

  5. 深入研究Visual studio 2017 RC新特性

    在[Xamarin+Prism开发详解三:Visual studio 2017 RC初体验]中分享了Visual studio 2017RC的大致情况,同时也发现大家对新的Visual Studio很 ...

  6. 【初码干货】使用阿里云对Web开发中的资源文件进行CDN加速的深入研究和实践

    提示:阅读本文需提前了解的相关知识 1.阿里云(https://www.aliyun.com) 2.阿里云CDN(https://www.aliyun.com/product/cdn) 3.阿里云OS ...

  7. 对一致性Hash算法,Java代码实现的深入研究

    一致性Hash算法 关于一致性Hash算法,在我之前的博文中已经有多次提到了,MemCache超详细解读一文中"一致性Hash算法"部分,对于为什么要使用一致性Hash算法.一致性 ...

  8. SQLSERVER聚集索引与非聚集索引的再次研究(下)

    SQLSERVER聚集索引与非聚集索引的再次研究(下) 上篇主要说了聚集索引和简单介绍了一下非聚集索引,相信大家一定对聚集索引和非聚集索引开始有一点了解了. 这篇文章只是作为参考,里面的观点不一定正确 ...

  9. 开源Word读写组件DocX 的深入研究和问题总结

    一. 前言 前两天看到了asxinyu大神的[原创]开源Word读写组件DocX介绍与入门,正好我也有类似的自动生成word文档得需求,于是便仔细的研究了这个DocX. 我也把它融入到我的项目当中并进 ...

随机推荐

  1. CentOS7配置Nodejs环境安装记录

    今天购买了阿里云服务器,系统选的是CentOS7,下面记录下在它上面安装Nodejs环境的过程,本次操作是直接连接的阿里云服务器的管理终端. 1.由于是纯净的环境,先通过以下命令安装nodejs编译及 ...

  2. PSAM读卡芯片TDA8007BHL开发

    WWT:Work Waiting Time ATR:Answer To Reset,复位应答 etu =F/Df 1.     PSAM概述和应用 PSAM(PurchaseSecure Access ...

  3. PowerShell 字符串操作符

    字符串操作符 格式化操作符 –F 在PowerShell文本操作符中非常重要,经常被用来增强数字类型和日期类型的可读性: "{0} diskettes per CD" -f (72 ...

  4. Qt编程之对QGraphicsItem点击右键弹出菜单

    就是对这个contextMenuEvent 事件重新实现,在这个事件函数中创建菜单,大概就是这样. void MyItem::contextMenuEvent(QGraphicsSceneContex ...

  5. 黑马程序员_Java面向对象2_继承

    4.面向对象_继承 4.1继承的概述 提高了代码的复用性. 让类与类之间产生了关系,有了这个关系,才有多态的特性. 注意:千万不要为了获取其他类的功能而去继承,简化代码而继承.必须是类与类之间有所属关 ...

  6. socket 网摘

    一.基本socket函数 Linux系统是通过提供套接字(socket)来进行网络编程的.网络的socket数据传输是一种特殊的I/O,socket也是一种文件描述符.socket也有一个类似于打 开 ...

  7. IDF实验室解题学习笔记1

    1.图片里的英文 图片可以有很多种打开方式,破解该题,需将图片下载下来. 对于图片,我们可以使用图片编辑软件,进行各种调明暗,变色调等操作. 我们还可以使用2进制或者16进制的文件打开方式打开.该图使 ...

  8. 深入理解linux网络技术内幕读书笔记(四)--通知链

    Table of Contents 1 概述 2 定义链 3 链注册 4 链上的通知事件 5 网络子系统的通知链 5.1 包裹函数 5.2 范例 6 测试实例 概述 [注意] 通知链只在内核子系统之间 ...

  9. hdu2817之整数快速幂

    A sequence of numbers Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Ot ...

  10. Zedboard甲诊opencv图像处理(二)

    通过前面的努力已经得到了n个轮廓了,现在要把最终的轮廓确定下来 ,然后进行特征提取. 先深入分析下轮廓和处理轮廓的方法:http://blog.csdn.net/hitwengqi/article/d ...