研究 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. 让C程序更高效的10种方法

    http://blog.jobbole.com/1198/ 代码之美,不仅在于为一个给定问题找到解决方案,而且还在代码的简单性.有效性.紧凑性和效率(内存).代码设计比实际执行更难 .因此,每一个程序 ...

  2. [HDU] 2063 过山车(二分图最大匹配)

    题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=2063 女生为X集合,男生为Y集合,求二分图最大匹配数即可. #include<cstdio> ...

  3. QuickTime 专业版 pro 注册码

    打开QuickTime Player下拉编辑菜单--选偏好设置--注册 Name: Dawn M Fredette Key: 4UJ2-5NLF-HFFA-9JW3-X2KV 重新启动 QuickTi ...

  4. Nexus Root Toolkit教程——刷机

    Nexus Root Toolkit是Nexus系列设备专属解锁.root.刷机.修复工具.本教程以Nexus7二代刷安卓5.0 Lollipop系统为实例演示刷机过程. 标签: 安卓5.0刷机教程 ...

  5. 转:AM335x启动流程(BootRom->MLO->Uboot)

    http://blog.chinaunix.net/uid-28458801-id-3486399.html 参考文件: 1,AM335x ARM Cortex-A8 Microprocessors ...

  6. 自定义Window进入和退出效果(转)

    看了android的源代码和资源文件,终于明白如何去修改设置Dialog和Activity的进入和退出效果了. 设置Dialog首先通过getWindow()方法获取它的窗口, 然后通过getAttr ...

  7. Codeforces 596D Wilbur and Trees

    http://codeforces.com/contest/596/problem/D 题目大意: 有n棵树排成一排,高度都为h. 主人公要去砍树,每次等概率地随机选择没倒的树中最左边的树或者最右边的 ...

  8. CentOS6.5切换 语言(附带6.5官方下载地址)

    1 在终端中输入命令[sudo vim /etc/sysconfig/i18n]来编辑i18n文件, 2 把“zh_CN.UTF-8”修改为“en_US.UTF-8”, 3 保存修改并退出,如果提示这 ...

  9. Android Studio:Unable to add window android.view.ViewRootImpl$W@5e2d85a -- permission denied for this window 第一行代码

    学习<第一行代码>的时候,出现的错误. java.lang.RuntimeException: Unable to start receiver com.example.sevenun.l ...

  10. 正则表达式获取URL参数

    使用到的正则表达式: [^\?&]?参数名=[^&]+ document.location.getURLPara = function (name) { var reg = new R ...