UIActivityViewController的使用#
UIActivityViewController
是iOS上为App实现多种服务的一个标准视图控制器,系统默认提供了很多的标准服务,如拷贝链接,添加到Safari阅读列表,还有就是多平台的分享,包括微博,Facebook,email等。其实看起来就是一个actionSheet。
我们的任务是负责配置、显示和关闭这个视图控制器,配置也就是为这个视图控制器提供数据源。当然,我们也可以根据需要自定义自己服务(通过继承UIActivity)。在iPad上,我们以popover的形式显示这个视图控制器;而在 iPhone 和 iPod touch上, 我们需要以模态的形式显示。
先写一个最基本的代码:
let image = UIImage(named: "iOS9")
let str = "hello iOS9"
let url = NSURL(string: "http://helloseed.io")
let items:[AnyObject] = [image!, str, url!];
self.presentViewController(vc, animated: true, completion: nil)
标准显示
可以看到,几句代码就可以显示出我们需要的controller了。Activity分为两类,图中可以看到它被分割线分为上下两部分,上面部分为Share(Objective-C为UIActivityCategoryShare)类型,下面部分为Action(Objective-C为UIActivityCategoryAction)类型。
下面我们添加如下代码:
vc.completionWithItemsHandler = {(activityType:String?, completed:Bool, returnedItems:[AnyObject]?, activityError:NSError?) -> Void in
if completed {
self.alert("成功")
}
vc.completionWithItemsHandler = nil
}
然后点击其中的一个item,这时会弹出成功的alert。没错,这个block属性就是用来处理点击后的回调。
几个参数说明:activityType
为被点击的服务类型;completed
标识服务是否执行成功;returnedItems
是一个包含NSExtensionItem
对象的数组;activityError
指出出错原因。更详细的参数说明可以参考官方文档
现在,我们再在调用presentViewController
方法之前添加一行代码:
vc.excludedActivityTypes = [UIActivityTypeMail, UIActivityTypeAddToReadingList, UIActivityTypeAssignToContact];
再次运行,可以发现少了Mail、Assign to Contact、Add to Reading List这三个item。是的,excludedActivityTypes
这个数组就是用来指定不需要那些服务的。我们可以将不需要的服务写进数组内,具体还有哪些服务,见文档。(注:现在所运行的环境都是在iOS8上的,iOS9后还添加了Notes(备忘录),和Reminders(提醒事项)这两个服务)
标准的基本上就这些,然并卵。。。
基本上,仅使用系统默认提供的服务是不够的,每个App有自己的需求,所以自定义服务是必然的。前面说到,通过继承
UIActivity
来实现自定义,下面来自定义几个常用的服务:微信Timeline,微信Session、新浪微博、拷贝链接。(这里就以微博和拷贝链接为例,其他都大同小异的)
- 先创建一个类名为:
CustomActivity
,继承于UIActivity
,以后其他自定义的Activity类直接继承它。代码如下:
import UIKit
class CustomActivity: UIActivity {
var title:String?
var image:UIImage?
var url:NSURL?
override class func activityCategory() -> UIActivityCategory {
return .Share
}
override func activityType() -> String? {
return NSStringFromClass(self.classForCoder)
}
/**
返回是否可以执行
- parameter activityItems: 从调用处传进来的items,可以通过这个items里面存放的类型数据来判断是否可以执行
- returns: 返回true,则这个activity就会在controller上出现;否则,则不会出现
*/
override func canPerformWithActivityItems(activityItems: [AnyObject]) -> Bool {
//只要items有数据,就返回true。
if activityItems.count > 0 {
return true
}
return false
}
/**
准备数据
- parameter activityItems: 数据对象数组
*/
override func prepareWithActivityItems(activityItems: [AnyObject]) {
for activityItem in activityItems {
if let title = activityItem as? String {
self.title = title
} else if let image = activityItem as? UIImage {
self.image = image
} else if let url = activityItem as? NSURL {
self.url = url
}
}
}
/**
执行点击
*/
// override func performActivity() {
// super.performActivity()
// print(self.title)
// print(self.image)
// print(self.url)
// }
}
几个需要我们override的方法的作用已经在注释上说明,就不多说了。
接着,我们创建一个WeiboActivity
,如下:
import UIKit
class WeiboActivity: CustomActivity {
override func activityTitle() -> String? {
return "新浪微博"
}
override func activityImage() -> UIImage? {
return UIImage(named: "weibo")
}
override func performActivity() {
super.performActivity()
//将需要分享的数据通过微博SDK进行分析
}
}
然后创建一个CopyLinkActivity
类,如下:
import UIKit
class CopyLinkActivity: CustomActivity {
override class func activityCategory() -> UIActivityCategory {
return .Action
}
override func activityTitle() -> String? {
return "拷贝链接"
}
override func activityImage() -> UIImage? {
return UIImage(named: "share_link")
}
override func canPerformWithActivityItems(activityItems: [AnyObject]) -> Bool {
//因为是拷贝链接,所有如果不存在NSURL对象,则返回false
for item in activityItems {
if let _ = item as? NSURL {
return true
}
}
return false
}
override func performActivity() {
super.performActivity()
//拷贝需要的链接
}
}
自定义工作告一段落,现在回到ViewController,将代码改成如下:
let image = UIImage(named: "seed")
let str = "hello iOS9"
let url = NSURL(string: "http://helloseed.io")
let items:[AnyObject] = [image!, str, url!];
let weibo = WeiboActivity() //实例化WeiboActivity
let copylink = CopyLinkActivity() //实例化CopyLinkActivity
let vc = UIActivityViewController(activityItems: items, applicationActivities: [weibo, copylink])
vc.excludedActivityTypes = [UIActivityTypeMail, UIActivityTypeAddToReadingList, UIActivityTypeAssignToContact];
self.presentViewController(vc, animated: true, completion: nil)
vc.completionWithItemsHandler = {(activityType:String?, completed:Bool, returnedItems:[AnyObject]?, activityError:NSError?) -> Void in
if completed {
self.alert("成功")
}
vc.completionWithItemsHandler = nil
}
执行程序:
自定义Activity
顺利完成。不过我们发现,点击自定义的activity后,不会调用completionWithItemsHandler
方法,即没有弹出成功。我的解决方法是,同样自定义一个closure(Objective-C中的block)来执行回调。于是,在CustomActivity
中添加:
var finishedBlock:(()-> Void)?
并将上面注释掉的方法performActivity
解注释。如下:
/**
执行点击
*/
override func performActivity() {
super.performActivity()
if let block = self.finishedBlock {
block()
}
self.activityDidFinish(true)
}
这样,在调用处想执行什么代码直接添加到finishedBlock
即可。
再啰嗦一下,其实我们可以连prepareWithActivityItems
都不需要override,title
,image
,url
也都不需要定义,CustomActivity
的子类也不需要overrideperformActivity
了。直接将要执行的代码放到finishedBlock
上,类似这样:
/**
执行点击
*/
override func performActivity() {
super.performActivity()
if let block = self.finishedBlock {
block()
}
self.activityDidFinish(true)
}
最后,为Activity提供的图片需要注意的一点:如果Activity的Category是Share,则不能是透明的,即关闭透明通道;如果Category是Action,则图片需要开启透明通道,因为系统需要将图片渲染成和标准的一样颜色(所以,不需要将图片颜色调成一致,系统会帮我们做),另外,圆角也是系统处理的。
Demo: https://github.com/linshaolie/UIActivityViewControllerDemo
参考文章:
https://github.com/nixzhu/dev-blog/blob/master/2014-04-22-ui-activity-viewcontroller.md
想获得第一手精彩文章,欢迎关注我的微信公众号:"iOS和Android干货"
扫一扫发现更多精彩文章
网友评论