iOS Widget开发
来源:互联网 发布:动漫周边在淘宝 编辑:程序博客网 时间:2024/06/03 21:53
讲述之前首先看下demo效果图:
然后再展示几个效果不错的 Widget app
demo 地址在此!欢迎star
一、Widget总览
- Widget 是 iOS8 推出第一版,在iOS 10 进行大幅度的优化
- Widget可以让用户更快地访问到其感兴趣的内容,官方的说法是用来呈现功能比较简单的,交互性不强的东西,在不打扰或者中断用户使用当前应用的前提下完成自己的功能点.对于这个说法,国内的开发者表示呵呵,因为几乎所有的 Widget都绑定了对应的点击事件
二、Widget代码实现
因为 Widget 属于单独的进程,因此需要再新建一个target:File -> New ->target
初次构建 UI 时,运行 Widget 后会发现,Widget左侧距离屏幕左侧始终有一段距离,导致效果不佳,可以通过下面的代理方法消除间距
// 取消widget默认的inset,让应用靠左- (UIEdgeInsets)widgetMarginInsetsForProposedMarginInsets:(UIEdgeInsets)defaultMarginInsets { return UIEdgeInsetsZero;}
- Widget 的收起、展开 则是通过这个代理方法:
/** activeDisplayMode有以下两种 NCWidgetDisplayModeCompact, // 收起模式 NCWidgetDisplayModeExpanded, // 展开模式 */- (void)widgetActiveDisplayModeDidChange:(NCWidgetDisplayMode)activeDisplayMode withMaximumSize:(CGSize)maxSize { if(activeDisplayMode == NCWidgetDisplayModeCompact) { // 尺寸只设置高度即可,因为宽度是固定的,设置了也不会有效果 self.preferredContentSize = CGSizeMake(0, 110); } else { self.preferredContentSize = CGSizeMake(0, 310); }}
在设置 UI 的过程中,若想使用本体 Target 中的类:
如果想使用Pod 管理的第三方库,那么只需要以下三步就可以愉快地玩耍了(比如我想使用 Masonry 布局)
1、 在podfile文件中
2、 按照如图所示配置configurations
3、 最后分别配置两个 Target 的 link Binanry当然有些第三方包含 source 文件的可能还需要别的操作,最简单粗暴的方式就是-->拖进去!
使用图片也是必不可少,然而 imageNamed: 和 imageWithContentsOfFile: 两种方式加载都不行,即使设置了文件的 target 为 Widget Extension,后来在其target 内部建立一个 .xcassets 文件即可加载图片
然而在 Widget Extension 里面新建类又出现了如下报错
- 造成这个的原因是新建的时候默认是 C header,而且没有指向对应的target,按照下图所示修改一下type,选一下target,再次编译就木有问题了
- 如果需要网络请求,记住在 Extension 的plist文件中添加App Transport Security Settings 属性
- 在开发过程中,那么怎么一直有个“Hello World”显示,最后看了一下原来是 Storyboard 加载,去 Storyboard 文件删除对应 label 即可
- 如果你的项目中要求纯代码
- 删除 Storyboard 文件和plist 对应键值对
- 添加 NSExtensionPrincipalClass 字段并设置为 TodayViewController
三、与 App 本体交互
与本体 app 进行交互之前,要明白的一个概念是:Widget 与 app 本身 是两个target,appId 也是独立的,因此 Widget 与本体 app 是通过 app group 进行交互
1、设置群组关系
在 本体 App 的 target > Capabilities添加 container 标识符
- 报错信息:[_NCWidgetExtensionContext openURL:completionHandler:]_block_invoke failed: Error Domain=NSOSStatusErrorDomain Code=-50 "(null) 如果报这个错说明 urlScheme有问题,没有标准对应,比如下划线识别等
2、设置 scheme 进行交互
- 设置 app 的 scheme 标识符
- 然后!就可以在 Widget 对应的点击事件里面
// 扫一扫按钮的点击事件- (void)scanBtnTapped:(UIButton *)sender { [self.extensionContext openURL:[NSURL URLWithString:@"wpfWidgetTest://action=richScan"] completionHandler:^(BOOL success) { NSLog(@"scanBtnTapped open url result:%d",success); }];}
- 在 app 本体的 AppDelegate 方法里面
// 处理 Widget 相关事件- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation { NSString* prefix = @"wpfWidgetTest://action="; NSString *urlString = [url absoluteString]; if ([urlString rangeOfString:prefix].location != NSNotFound) { NSString *action = [urlString substringFromIndex:prefix.length]; if ([action isEqualToString:@"richScan"]) { // 进入到扫一扫页面 [self.rootVC transferToRichScanVC]; } else if ([action isEqualToString:@"web"]) { // 进入到 web 活动页 [self.rootVC transferToWebVCWithUrlString:@"webTest"]; } } return YES;}
- 数据共享:widget项目必然经常要和主项目共享数据,可以通过NSUserDefault,注意和平时用有些不同,创建UserDefault的时候,要指定groupid。上代码:
// widget项目里取数据+ (NSString*)widgetStringForKey:(NSString*)defaultName { NSUserDefaults*shared = [[NSUserDefaultsalloc] initWithSuiteName:@"group.com.widgetTest"]; return[shared stringForKey:defaultName];}// 主项目里存数据+ (void)widgetSetObject:(id)value forKey:(NSString*)defaultName { NSUserDefaults*shared = [[NSUserDefaultsalloc] initWithSuiteName:@"group.com.widgetTest"]; [shared setObject:value forKey:defaultName]; [shared synchronize];}#warning 涉及到大量数据交互也可以使用 NSFileManager 进行数据共享
在demo中,实现了从Widget入口 点击未读消息后,下次不再展示该未读消息项
四、关于刷新时机
- Widget 自身的更新机制,是进入到 Widget 页面后(iOS 10 左滑,之前是下拉),先执行 viewDidLoad 方法,然后是viewWillAppear 方法,但是经测验,Widget 页面在屏幕消失超过两秒后(手机没有停留在 Widget 页面 或者 停留在别的app 的Widget页面,自己的没显示)
- 由于以上特性,更新代码最好写在 viewWillAppear 方法里面,对于更新时效性特别强的,比如天气类 app,这种最好就是 在该方法里面添加一个 NSTimer 定时进行刷新,在viewWillDisAppear 方法中 进行 取消NSTimer invalidate定时更新即可
- 知乎、得到 app的 Widget,只要走 viewDidLoad 方法就会闪一下(如下图),因为每次Widget加载请求的数据后会进行替换造成的。这里可以做个缓存优化,判断如果请求来的数据和当前数据内容一致,那么就不进行刷新列表操作
五、关于 iOS8 适配
- iOS8、9是老式的下拉刷新,并没有折叠和展开功能,默认的Widget高度为self.preferredContentSize设置的高度
- iOS8 默认的背景是黑色磨砂效果,iOS10默认的背景色是白色磨砂效果。因此在控件颜色上做下适配
- iOS8下所有组件默认右移30pt
六、其他注意点
当程序内存不足时,苹果优先会杀死扩展,因此需要注意内存的管理。
在配置team是账号需要一致(免费账号不行,需要付费的账号),上传包的时候一定注意选择 Product -> Archive -> 选择 distribution 模式!
3D touch 对应的也有Widget!?答案是 YES!,只要设置了3D touch,Widget的第一栏就会自动显示。但是如果有多个widget的话,还需要在 info.plist 指定相应的main target!
Extension 证书配置指南
官网说明
一直很心仪的app --> Things 关于widget的介绍
几个精致的 Widget app
在模拟器上进行3D touch 测试
再次附上 demo Github 地址,欢迎star
作者:si1ence
链接:http://www.jianshu.com/p/1a3bd243f77c
來源:简书
- iOS开发-widget基础
- iOS Widget开发
- iOS widget开发
- iOS Widget开发
- iOS Widget开发
- iOS开发之构建Widget
- iOS开发之构建Widget
- iOS开发之构建Widget
- iOS开发之widget实现
- ios 开发之widget实现
- iOS Widget && Today Extension 开发
- ios 10 开发-widget实现
- iOS Today Extension开发(Widget)
- iOS -- Widget 开发之 Today Extension
- iOS 10 —— widget开发详解
- iOS之widget开发(Today Extension)
- iOS 开发之Widget的开发及使用(上)
- iOS 开发之Widget的开发及使用(下)
- 不能确定接口给的是空数组空字符怎么判断显示内容呢
- Android UI系列之侧滑粘稠效果的实现
- 發送mail 心得
- SQL(高级查询)
- iFunk,科技享乐新主张
- iOS Widget开发
- JVM 工作原理和流程
- 在线机器学习书籍
- 梳理社招面试以及浅述对程序员职业生涯的看法《转》
- C语言课程设计-教师工作管理系统
- 使用Builder模式封装Dialog和PopupWindow
- centos7 编译安装tensorflow1.2
- jpa nulls last 不起作用
- Java注解(Annotation)详解(四)——注解反射生成SQL语句