UIActivityViewController的使用

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

再次运行,可以发现少了MailAssign to ContactAdd to Reading List这三个item。是的,excludedActivityTypes这个数组就是用来指定不需要那些服务的。我们可以将不需要的服务写进数组内,具体还有哪些服务,见文档。(注:现在所运行的环境都是在iOS8上的,iOS9后还添加了Notes(备忘录),和Reminders(提醒事项)这两个服务)

取消显示不必要是item

标准的基本上就这些,然并卵。。。
基本上,仅使用系统默认提供的服务是不够的,每个App有自己的需求,所以自定义服务是必然的。前面说到,通过继承UIActivity来实现自定义,下面来自定义几个常用的服务:微信Timeline,微信Session、新浪微博、拷贝链接。(这里就以微博和拷贝链接为例,其他都大同小异的)

  1. 先创建一个类名为: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干货"

扫一扫发现更多精彩文章
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,392评论 25 707
  • 品牌不仅仅是面向市场、用户、行业的品牌与产品本身,其中品牌形象与品牌元素、产品包装部分是引导着用户认同价值观。在品...
    商智执行家阅读 466评论 0 1
  • 这是几个零散的故事,发生在不同的人之间。各种各样的感情,让人在多年后回想起还能忍不住微笑。 〈一〉 有人说...
    性别猫阅读 364评论 0 0
  • 依恋关系应该是属于心理治疗流派中客体关系里分出来的一套理论。而且这套理论是从试验中得出来的,所以这套理论的内容是真...
    有趣的谷粒阅读 1,363评论 0 0
  • 宝宝,你握着我的手的时候,我的手一动不动。在你那双有点温热的手里,我的手就像是一只深海底的鱼,安静。我的内心深处,...
    涛之源阅读 211评论 0 0