您的位置:首页 > 产品设计 > UI/UE

UIActivityViewController的相关用法(一)--URL的发送和接收

2014-12-25 15:06 351 查看
UIActivityViewController 是一个能为应用程序提供服务的试图控制器。操作系统已经提供了一些标准服务,诸如 复制内容到剪切板,提交内容到社交网站,通过 email 或 短信发送内容等。应用程序也可以自定义服务。在ios8中系统的一些应用可以直接通过action分享给qq好友和微信好友,是因为腾讯增加了Extension,第三方的app不注册腾讯的开发者是无法使用的。

UIActivityViewController 的Action分为两类,在UIAction的定义中可以查看到:

UIKIT_EXTERN NSString *const UIActivityTypePostToFacebook     NS_AVAILABLE_IOS(6_0);
UIKIT_EXTERN NSString *const UIActivityTypePostToTwitter      NS_AVAILABLE_IOS(6_0);
UIKIT_EXTERN NSString *const UIActivityTypePostToWeibo        NS_AVAILABLE_IOS(6_0);    // SinaWeibo
UIKIT_EXTERN NSString *const UIActivityTypeMessage            NS_AVAILABLE_IOS(6_0);
UIKIT_EXTERN NSString *const UIActivityTypeMail               NS_AVAILABLE_IOS(6_0);
UIKIT_EXTERN NSString *const UIActivityTypePrint              NS_AVAILABLE_IOS(6_0);
UIKIT_EXTERN NSString *const UIActivityTypeCopyToPasteboard   NS_AVAILABLE_IOS(6_0);
UIKIT_EXTERN NSString *const UIActivityTypeAssignToContact    NS_AVAILABLE_IOS(6_0);
UIKIT_EXTERN NSString *const UIActivityTypeSaveToCameraRoll   NS_AVAILABLE_IOS(6_0);
UIKIT_EXTERN NSString *const UIActivityTypeAddToReadingList   NS_AVAILABLE_IOS(7_0);
UIKIT_EXTERN NSString *const UIActivityTypePostToFlickr       NS_AVAILABLE_IOS(7_0);
UIKIT_EXTERN NSString *const UIActivityTypePostToVimeo        NS_AVAILABLE_IOS(7_0);
UIKIT_EXTERN NSString *const UIActivityTypePostToTencentWeibo NS_AVAILABLE_IOS(7_0);
UIKIT_EXTERN NSString *const UIActivityTypeAirDrop            NS_AVAILABLE_IOS(7_0);

typedef NS_ENUM(NSInteger, UIActivityCategory) {
UIActivityCategoryAction,
UIActivityCategoryShare,
} NS_ENUM_AVAILABLE_IOS(7_0);


应用程序要复制配置、呈现和消除 UIActivityViewController。UIActivityViewContoller 的配置需要明确指出控制器要表现出的数据对象。

下面的代码源自于苹果官方提供的AirDropSample项目,按照本人理解的顺序解析,每个人理解的角度不一样,有偏差请以官方代码和释义为准。

一:通过UIActivityViewController发送/接收URL(文本等同之)

发送:用一个URLViewController来管理(

如果app用URL发送元数据,应该创建一个包含该url的容器类,此类必须要实现 UIActivityItemSource 协议。

)

#import <UIKit/UIKit.h>

@interface UrlViewController : UIViewController
@end

#import "UrlViewController.h"
#import "Utilities.h"
#import "UrlContainer.h"

@interface UrlViewController ()<UITextFieldDelegate>
@property (weak, nonatomic) IBOutlet UITextField *textField;
@property (strong, nonatomic) UrlContainer *urlContainer;

@property (strong, nonatomic) UIPopoverController *popOverController;

@end

@implementation UrlViewController

- (void)viewDidLoad {
[super viewDidLoad];

// 加载收到的url, 如果没有收到的url返回nil
NSURL *url = [Utilities loadUrl];
if (!url) {
url = [NSURL URLWithString:@"hsun://test/one/two?key1=value1"];
}
//    NSLog(@"host:%@, user:%@, path:%@, fragment:%@, parameterString:%@, query:%@, relativePath:%@", url.host, url.user, url.path, url.fragment, url.parameterString, url.query, url.relativePath);
// 初始化item容器
self.urlContainer = [[UrlContainer alloc] initWithUrl:url];
// 显示容器中的URL内容
self.textField.text = [self stringWithoutURLScheme:self.urlContainer.url];
}

-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// 为控制器注册通知,接收到URL, 保存窗口将要呈现
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadUrl) name:@"ReceiveURLViewController" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(saveWindowWillAppear) name:@"SaveWindowWillAppear" object:nil];
}

-(void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
// view 消失时移除通知
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"ReceiveURLViewController" object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"SaveWindowWillAppear" object:nil];
}

- (IBAction)share:(id)sender {
// 用实现了 UIActivityItemSource协议的item容器初始化,容器类的定义在下面
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:@[self.urlContainer] applicationActivities:nil];

/***
action 分为两种 :
UIActivityCategoryAction,
UIActivityCategoryShare
如果有不想展示的Share 或者 Action,可以通过如下实现
activityViewController.excludedActivityTypes = @[UIActivityTypePrint];
   选择Action即可发送容器内的URL了,至此发送URL(文本)完成
***/

// iphone 直接呈现
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone) {
[self presentViewController:activityViewController animated:YES completion:nil];
}
else // ipad 需要用PopOver
{
if([self.popOverController isPopoverVisible])
{
[self.popOverController dismissPopoverAnimated:YES];
}
else
{
self.popOverController = [[UIPopoverController alloc] initWithContentViewController:activityViewController];
[self.popOverController presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}

}

}

#pragma mark - UITextFieldDelegate
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
[self.textField resignFirstResponder];
return YES;
}
-(void)textFieldDidEndEditing:(UITextField *)textField
{
// 输入的如果不同于url容器中的内容,重新为其赋值
if(![self.textField.text isEqualToString:[self stringWithoutURLScheme:self.urlContainer.url]])
{
NSString *urlString = [NSString stringWithFormat:@"hsun://%@", self.textField.text];
self.urlContainer.url = [NSURL URLWithString:urlString];
}
}

#pragma mark - String of url without scheme
-(NSString *)stringWithoutURLScheme:(NSURL*)url
{
NSString *scheme = [[url scheme] stringByAppendingString:@"://"];
// 从scheme之后截取
return [[url absoluteString] substringFromIndex:scheme.length];
}

#pragma mark - Handle received notifications
-(void)reloadUrl
{
// 收到通知后加载收到的url
NSURL *receivedUrl = [Utilities loadUrl];
if(receivedUrl)
{
self.urlContainer.url = receivedUrl;
self.textField.text = [self stringWithoutURLScheme:receivedUrl];
}
}

-(void)saveWindowWillAppear
{
// 处理窗口将要呈现的通知
[self.textField resignFirstResponder];
}

@end


关于实现UIActivityItemSource的URL(文本)容器类,

#import <Foundation/Foundation.h>

@interface UrlContainer : NSObject<UIActivityItemSource>

@property (nonatomic, strong) NSURL *url;
-(instancetype)initWithUrl:(NSURL*)url;

@end

#import "UrlContainer.h"
#import "UIImage+resize.h"

@implementation UrlContainer

-(instancetype)initWithUrl:(NSURL *)url
{
self = [super init];
if(self)
{
self.url = url;
}
return self;
}

#pragma mark - UIActivityItemSource
-(id)activityViewControllerPlaceholderItem:(UIActivityViewController *)activityViewController
{
// 占位,将要返回的类型
return self.url;
}

-(id)activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(NSString *)activityType
{
// 直接返回容器的url
return self.url;
}
-(UIImage*)activityViewController:(UIActivityViewController *)activityViewController thumbnailImageForActivityType:(NSString *)activityType suggestedSize:(CGSize)size
{
// 为item提供缩略图,大小为建议的大小
// 用自定义的UIImage的Category resize 类方法处理图片为缩略图
return [UIImage imageWithImage:[UIImage imageNamed:@"Beads.png"] scaledToFitToSize:size];
}
@end


自定义的UIImage+resize

#import <UIKit/UIKit.h>

@interface UIImage (resize)

+(UIImage*)imageWithImage:(UIImage*)image scaledToFitToSize:(CGSize)size;
+(UIImage*)imageWithImage:(UIImage*)image scaledToFillToSize:(CGSize)size;

@end

#import "UIImage+resize.h"

@implementation UIImage (resize)

// 根据尺寸和矩形重绘图片
+(UIImage*)imageWithImage:(UIImage*)image scaledToSize:(CGSize)size inRect:(CGRect)rect
{
if ([UIScreen mainScreen].scale == 2.0) {
UIGraphicsBeginImageContextWithOptions(size, YES, 2.0);
}
else
{
UIGraphicsBeginImageContext(size);
}
[image drawInRect:rect];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

return newImage;
}

+(UIImage*)imageWithImage:(UIImage *)image scaledToFitToSize:(CGSize)size
{
// 如果图片原尺寸已经小于要Scaled尺寸,不作处理
if(image.size.height < size.height && image.size.width < size.width)
{
return [image copy];
}

// 根据缩放后的宽高,得到缩放比例
CGFloat widthScaled = size.width / image.size.width;
CGFloat heigtScaled = size.height / image.size.height;
CGFloat scaledFactor = widthScaled > heigtScaled ? heigtScaled : widthScaled;

// 缩放图片的尺寸
CGSize scaledSize = CGSizeMake(image.size.width * scaledFactor, image.size.height * scaledFactor);
return [UIImage imageWithImage:image scaledToSize:scaledSize inRect:CGRectMake(0.0, 0.0, scaledSize.width, scaledSize.height)];
}

+(UIImage*)imageWithImage:(UIImage *)image scaledToFillToSize:(CGSize)size
{
// 如果图片原尺寸已经小于要Scaled尺寸,不作处理
if(image.size.height < size.height && image.size.width < size.width)
{
return [image copy];
}

// 根据缩放后的宽高,得到缩放比例
CGFloat widthScaled = size.width / image.size.width;
CGFloat heigtScaled = size.height / image.size.height;
CGFloat scaledFactor = widthScaled > heigtScaled ? heigtScaled : widthScaled;
// 缩放图片的尺寸
CGSize scaledSize = CGSizeMake(image.size.width * scaledFactor, image.size.height * scaledFactor);

CGPoint scaledPoint;
widthScaled > heigtScaled ? (scaledPoint.y = (size.height - scaledSize.height)/2) : (scaledPoint.x = (size.width - scaledSize.height)/2);

return [UIImage imageWithImage:image scaledToSize:size inRect:CGRectMake(scaledPoint.x, scaledPoint.y, scaledSize.width, scaledSize.height)];
}

@end


接收:通过AirDrop接收URL(

要想接收一个自定义了scheme的URL,app需要注册为能接收这个scheme。在项目的Target下的Info节点,有URL Types,在此注册, 或者用代码注册,详细可参考此链接http://www.cocoachina.com/industry/20140522/8514.html



AirDrop接收到内容后会调用 UIApplication 的委托方法 application:openURL:sourceApplication:annotation,关于此方法的详细可以查看文档;

#import "AppDelegate.h"
#import "RootTableViewController.h"
#import "Utilities.h"

@interface AppDelegate ()

@property (nonatomic, strong) UINavigationController *navController;
@property (nonatomic, strong) RootTableViewController *rootTableViewController;
@property (nonatomic, strong) UIWindow *saveReceivedWindow;

@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

self.navController = [[UIStoryboard storyboardWithName:@"Main.stroyboard" bundle:nil] instantiateInitialViewController];
if(self.navController)
{
self.rootTableViewController = [[self.navController viewControllers] firstObject];
}

return YES;
}

-(void)applicationDidBecomeActive:(UIApplication *)application
{
NSLog(@"%@", NSStringFromSelector(_cmd));
}

-(BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
if (url) {
//在此处理接收到的url
// 需要校验收到的是否是app需要的。saveReceivedWindow是为了接收数据类型而设的变量
if ([url.scheme isEqualToString:@"hsun"]) {
// 保存url到文档中
[Utilities saveUrl:url];
// 广播收到URL的通知,如果UrlViewController处于显示状态则会收到此通知,然后重新从文档中加载新保存的url内容
[[NSNotificationCenter defaultCenter] postNotificationName:@"ReceiveURLViewController" object:nil];

//如果UrlViewController没有显示,调用根控制器显示
if ([self.navController.visibleViewController isEqual:self.rootTableViewController] && !self.saveReceivedWindow) {
[self.rootTableViewController showUrlViewController];
}
}
}
return YES;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: