iOS Widget开发
前言:
想了解什么是Widget的童鞋请绕道,想在项目中添加Widget的同学,请耐心往下看
首先看一下我们需要实现的效果:仿网易云音乐和仿支付宝两个效果
总效果图(左) 仿网易云音乐展开后的效果图(右)
一、打开你的Project,添加一个Today Extension
首先,打开Target,然后点左下角的“+”,在“iOS”选项下边找到Application Extension,然后选择“Today Extension”,如图1、图2所示:
图1 添加Target
图2 找到Today Extension
然后点击Next,填写Target名称,这里是“HJFirstWidget”,下一步会有一个**的弹窗,点击**按钮,如图3所示
图3 **Target
**之后,就添加好了,如图4所示,这时候你需要改Deployment Target,也就是最低支持的系统版本,需要注意的是Widget是iOS 8的新特性,因此此处的Deployment Target不能低于iOS 8.0;
图4 添加Today Extension完成以及需改Deployment Target示意图
这时候,运行项目就可以在通知页面看到一个空的Widget效果了,此时默认的视图控制器是TodayViewController,与之对应的是一个叫“MainInterface”的storyboard,如果需要纯代码布局,那么就要在plist文件最下边的NSExtension里修改一些配置,删除NSExtensionMainStoryboard键值对,新增NSExtensionPrincipalClass键值对,修改之前如图5所示,修改后如图6所示
图5 未修改配置的示意图
图6 修改配置后的示意图
需要说明的是:我们添加的Target叫Extension,最初创建的项目叫Containing APP
运行Containing APP,效果图如图7所示
图7 更改完配置后运行效果图
到这一步呢,项目基本成型,只需要我们在TodayViewController里边添加相应的空间即可实现相应的效果,下边我们将实现Widget最难也是最重要的功能
二、共享数据
要想通过Widget和Containing APP共享数据需要对他们分别进行配置,首先我们对Containing APP配置
打开Target,点击capability选项,找到APP Groups,点击右侧打开按钮,并添加Item,如图8 所示,配置完成之后再项目中会看淡一个后缀为.entitlements的文件;
图8 打开APP Groups以及添加Item示意图
然后配置Widget,操作同上步,操作完成后效果图如图9所示
图9 配置Widget完成后效果图
此时配置已经完成,通过相应代码即可实现数据共享,我们都知道,Extension 和 Containing APP之间共享数据的方式有两种,NSUserDefaults和NSFileManager,
1.通过NSFileManager存取:
存数据:
/** 通过NSFileManager存数据 @return 是否存储成功 */ - (BOOL)saveDataByNSFileManager { NSError *err = nil; /** 这里的groupIdentifier是在APP Groups里添加的Item **/ NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.hjfirst"]; containerURL = [containerURL URLByAppendingPathComponent:@"Library/Caches/widget"]; NSString *value = @"你要存的内容"; BOOL result = [value writeToURL:containerURL atomically:YES encoding:NSUTF8StringEncoding error:&err]; if (!result) { NSLog(@"存入数据失败,原因 : %@",err); } else { NSLog(@"存入数据成功,数据 : %@ success.",value); } return result; }
取数据:
/** 通过NSFileManager读取数据 @return 读取到的数据 */ - (NSString *)readDataByNSFileManager { NSError *err = nil; NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.hjfirst"]; containerURL = [containerURL URLByAppendingPathComponent:@"Library/Caches/widget"]; NSString *value = [NSString stringWithContentsOfURL:containerURL encoding:NSUTF8StringEncoding error:&err]; return value; }
2.通过NSUSerDefaults来共享数据
存数据:
/** 这里是采用NSUserDefaults来实现 **/ NSUserDefaults *sharedDefault = [[NSUserDefaults alloc] initWithSuiteName:@"group.hjfirst"]; [sharedDefault setObject:@{@"name" : [_titleArray objectAtIndex:sender.tag - 120]} forKey:@"firstStatus"]; [sharedDefault setBool:NO forKey:@"isSendData"]; [sharedDefault synchronize];
取数据
/** 这是一个获取Today Extension数据的例子 **/ NSUserDefaults *sharedDefault = [[NSUserDefaults alloc] initWithSuiteName:@"group.hjfirst"]; NSLog(@"共享的数据 : %@",[sharedDefault objectForKey:@"firstStatus"]);
三、通过Extension唤醒Containing APP
如果想通过Extension唤醒Containing APP,需要在Containing APP的Target进行配置,在Info的URL Types里边新增一项内容,配置后效果图如图10所示
图10 配置Containing APP效果图
配置完上述信息之后,就可以通过代码唤醒Containing APP,示例代码如下,其中://后边的内容是传递的参数,用以区分响应不同的事件
/* 这里的URL是有固定格式的,://前边的“hjWidgetDemo”是Containing APP添加的URL Types里添加的URL Schemes,这里是必须一致,否则会跳转失败的 */ NSString *urlString = [NSString stringWithFormat:@"hjWidgetDemo://action=%ld",sender.tag-120]; [self.extensionContext openURL:[NSURL URLWithString:urlString] completionHandler:^(BOOL success) { if (success == YES) { NSLog(@"跳转成功"); } else { NSLog(@"跳转失败"); } }];
四、iOS 10新特性
Widget可以折叠和展开,示例代码:
/* 设置Widget的样式,这是iOS 10的新特性,也就是所谓的“折叠”、“打开”模式, NCWidgetDisplayModeCompact, // Fixed height NCWidgetDisplayModeExpanded, // Variable height */ self.extensionContext.widgetLargestAvailableDisplayMode = NCWidgetDisplayModeExpanded;
系统封装的有点击折叠或者展开按钮的方法:
/** 这是Widget改变展示样式时候的回调 @param activeDisplayMode activeDisplayMode @param maxSize 尺寸 */ - (void)widgetActiveDisplayModeDidChange:(NCWidgetDisplayMode)activeDisplayMode withMaximumSize:(CGSize)maxSize { }
最终效果图为:
注意事项:
- Widget的展开和折叠是iOS 10的新特性,在iOS 8 到iOS 10 之间的系统只支持类似于折叠起来的效果;
- 如果需要自定义Widget某一部分控件的背景颜色,需要设计透明度,因为TodayViewController的背景色有透明度的,在不同颜色桌面壁纸上显示效果有较大差异;
- Widget目前暂不支持输入内容,只能做展示以及点击事件,也就是说不能再TodayViewController里边添加输入类的控件,比如说UITextField、UITextView等;
特别说明:如果发现错误或者不合理的地方,恳请批评指正
源码下载地址:https://github.com/HJZone/HJWidgetDemo