美文网首页IOSSwiftBlog带我飞2
UIActivityViewController的使用

UIActivityViewController的使用

作者: 木木烈少 | 来源:发表于2015-10-04 14:22 被阅读7018次

    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干货"

    扫一扫发现更多精彩文章

    相关文章

      网友评论

      • ljqjbb:大神,那俩 More 按钮能不能给它删了?
        木木烈少:@ljqjbb apple是没提供让你隐藏的方法啦,不过你倒可以试试去分析它的布局结构,看能不能将它remove掉
        ljqjbb:@木木少烈 别扭 而且测试让我删!
        木木烈少:好像没提供这个接口,你删掉是为了不让用户分享到其他平台还是看着别扭呢
      • JinkeyAI:所以excludedActivityTypes怎么设置才可以不显示Notes(备忘录),和Reminders(提醒事项)??
        chencheng0330:@BohrIsLay actvc.excludedActivityTypes = [.postToFacebook, .postToTwitter, .message, .mail, .print, .assignToContact, .saveToCameraRoll, .addToReadingList, .postToFlickr, .postToVimeo, .airDrop, .openInIBooks, .init(rawValue: "com.apple.reminders.RemindersEditorExtension"), .init(rawValue: "com.apple.mobilenotes.SharingExtension"), .init(rawValue: "com.apple.UIKit.activity.CopyToPasteboard")]
        BohrIsLay:找到方法了没有呀,分享下
      • newbiecoder:学习了 谢谢!
      • 一个努力的boy:棒
        木木烈少:@一个努力的boy 互相促进哈
      • Dee_Das:谢谢
      • ONEWJ:我也需要😄
        Damon4Zhou:@木木少烈 大神 swift和oc都很666啊
        ONEWJ:@林少烈 谢谢分享👍🏻
        木木烈少:@筱嫄 Demo已上传:https://github.com/linshaolie/blog/tree/master/UIActivityViewControllerDemo

      本文标题:UIActivityViewController的使用

      本文链接:https://www.haomeiwen.com/subject/mvpgcttx.html