iOS - Widget 小部件
1、Widget
iOS extension 的出现,方便了用户查看应用的服务,比如用户可以在 Today 的 widgets 中查看应用的简略信息,然后点击进入相关的应用界面。
2、添加 Widget
添加 Widget 流程
- 1、添加 Today Extension
- 2、绘制 UI
- 3、调起 app
- 4 、数据共享
2.1 添加 Today Extension
在 Xcode菜单 => File => New => Target.. => 中选择 Today Extension
2.2 绘制 UI
创建 Today Extension 时会默认创建 MainInterface.storyboard,可以在里面绘制显示的 Widget 内容,也可以使用代码绘制 UI。
设置 Widget 展示视图的大小。关于 Widget 的背景色,以及具体展示的内容大家按需绘制。
- (void)viewDidLoad {
[super viewDidLoad]; // 设置 Widget 展示视图的大小
self.preferredContentSize = CGSizeMake([UIScreen mainScreen].bounds.size.width, 100); self.view.backgroundColor = [UIColor yellowColor];
}
在 iOS8 - iOS9 中运行程序后,会发现一个问题:绘制的内容与左侧边界有一定距离(约 30px)。如何解决这个问题呢,NCWidgetProviding 协议给出了解决方案。iOS10 中不存在这个问题。
// 实现 NCWidgetProviding 协议方法
- (UIEdgeInsets)widgetMarginInsetsForProposedMarginInsets:(UIEdgeInsets)defaultMarginInsets {
return UIEdgeInsetsMake(0, 0, 0, 0);
}
2.3 调起 app
因为 extension 和 containing app 是两个完全独立的进程,所以它们之间不能直接通信(不能像应用内部点击按钮,跳转到指定页面)。为了实现 Widget 调起 app,这里通过 openURL 的方式来启动 containing app。
在 containing app 中设置 URL Schemes
在 extension 的 ViewController 中添加如下代码。
// 通过 extensionContext 借助 host app 调起 app // TodayWidget 为在 containing app 中设置的 URL Schemes
[self.extensionContext openURL:[NSURL URLWithString:@"TodayWidget://"] completionHandler:^(BOOL success) { NSLog(@"open url result:%d", success);
}];
2.4 数据共享
通过 App Groups 提供的同一 group 内 app 共同读写区域,可以用 NSUserDefaults 和 NSFileManager 两种方式实现 extension 和 containing app 之间的数据共享。
- 通过 NSUserDefaults 共享数据
保存数据
- (void)saveDataByNSUserDefaults { NSUserDefaults *shared = [[NSUserDefaults alloc] initWithSuiteName:@"group.qianqianstudio.freeInHouse"];
[shared setObject:@"asdfasdf" forKey:@"widget"];
[shared synchronize];
}
读取数据
- (NSString *)readDataFromNSUserDefaults { NSUserDefaults *shared = [[NSUserDefaults alloc] initWithSuiteName:@"group.qianqianstudio.freeInHouse"];
NSString *value = [shared valueForKey:@"widget"];
return value;
}
- 通过 NSFileManager 共享数据
保存数据
- (BOOL)saveDataByNSFileManager { NSError * error = nil; NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.qianqianstudio.freeInHouse"];
containerURL = [containerURL URLByAppendingPathComponent:@"Library/Caches/widget"];
NSString *value = @"asdfasdfasf";
BOOL result = [value writeToURL:containerURL atomically:YES encoding:NSUTF8StringEncoding error:&error]; if (!result) {
NSLog(@"%@", error);
} else {
NSLog(@"save value:%@ success.", value);
} return result;
}
读取数据
- (NSString *)readDataByNSFileManager { NSError *error = nil; NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.qianqianstudio.freeInHouse"];
containerURL = [containerURL URLByAppendingPathComponent:@"Library/Caches/widget"];
NSString *value = [NSString stringWithContentsOfURL:containerURL encoding:NSUTF8StringEncoding error:& error]; return value;
}
3、设置 Widget
1、Widget 中展开、折叠
iOS10 在 NSExtensionContext 中,新添了 widgetLargestAvailableDisplayMode 属性,来确认当前 Widget 是展开还是折叠状态。所以,先在 viewWillAppear 中设置 Widget 的 mode 为展开。
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated]; self.extensionContext.widgetLargestAvailableDisplayMode = NCWidgetDisplayModeExpanded;
}
然后,就是展开和折叠的处理了。在 NCWidgetProviding 协议中,新添了这个方法 widgetActiveDisplayModeDidChange。
- (void)widgetActiveDisplayModeDidChange:(NCWidgetDisplayMode)activeDisplayMode withMaximumSize:(CGSize)maxSize { if (activeDisplayMode == NCWidgetDisplayModeCompact) {
self.preferredContentSize = CGSizeMake([UIScreen mainScreen].bounds.size.width, 110);
} else {
self.preferredContentSize = CGSizeMake([UIScreen mainScreen].bounds.size.width, 300);
}
}
2、启动 app 后,第一次显示的是折叠,而不是展开 ?
- 这个问题,归咎于 preferredContentSize 的设置,确认 Widget 的 mode 之前,不要设置这个值。在 widgetActiveDisplayModeDidChange 中设置展开或折叠状态下 Widget 的高度,iOS10 环境下在这里设置高度也就足够了。
3、为什么有时展开或折叠 "失灵" 了,没有对应的展开或折叠呢 ?
- 这个问题的前提,肯定是你展开、折叠对应的 Widget 高度不一样,只是看到了右上角按钮内容改变,但高度却没有变。
- 这个问题的原因在于,点击展开、折叠按钮修改了 Widget 的 mode 之后,却没有设置对应的高度 preferredContentSize。怎么办呢?mode 改变后,设置对应状态下的高度即可。
4、真机调试 Widget
真机调试 Widget,牵扯到配置 group。首先我们的宿主 app id 为 com.qianqianstudio.TodayWidget, Today widget 插件的 bundle id 为 com.qianqianstudio.TodayWidget.Widget 这里我们需要注意,widget 的 bundle id 必须以宿主 bundle id 作为前缀。然后它俩之间建立的 group id 为 group.qianqianstudio.freeInHouse(可以取任意名)。
-
Identifiers => App Groups 里添加一个 app group id 为:group.qianqianstudio.freeInHouse
创建 app id。创建的时候选择 Explict App ID,App Services 里面勾选上 App Groups
主 app
widget
配置 provisioning profile(这里不再赘述 certificate 的生成步骤,添加 device 等),此时因为选择了勾选了 App Groups 这个 service 的 app id,所以可以看到 enabled services 那里有此项。
iOS - Widget 小部件的更多相关文章
- Android简易实战教程--第十四话《模仿金山助手创建桌面Widget小部件》
打开谷歌api,对widget小部件做如下说明: App Widgets are miniature application views that can be embedded in otherap ...
- 从Hello World说起(Dart)到“几乎所有东西都是Widget”小部件。
import 'package:flutter/material.dart'; void main() => runApp(new MyApp()); class MyApp extends S ...
- Odoo14 自定义widget小部件
不多说先上源码. 1 odoo.define('my_company_users_widget', function (require) { 2 "use strict"; 3 4 ...
- Android Widget 小部件(一) 简单实现
在屏幕上加入Widget:或长按屏幕空白处,或找到WidgetPreview App选择. 原生系统4.0下面使用长按方式,4.0及以上 打开WIDGETS 创建Widget的一般步骤: 在menif ...
- Android Widget 小部件(四---完结) 使用ListView、GridView、StackView、ViewFlipper展示Widget
官方有话这样说: A RemoteViews object (and, consequently, an App Widget) can support the following layout cl ...
- django中widget小部件
1. 处理 input 的部件 TextInput NumberInput EmailInput URLInput PasswordInput HiddenInput DateInput Dat ...
- Android Widget 小部件(三) 在Activity中加入Widget
package com.stone.ui; import static android.util.Log.d; import android.app.Activity; import android. ...
- yii2小部件(widget)
一.创建一个简单的小部件 namespace common\components; //common需要自己先设定一个别名 use yii\base\Widget; //小部件需要继承的基类 use ...
- Android-RemoteView-桌面小部件
Android-RemoteView-桌面小部件 学习自 <Android开发艺术探索> https://developer.android.google.cn/guide/topics/ ...
随机推荐
- 内存泄露:*.hprof
使用Memory Analyzer tool(MAT)分析内存泄漏 转账地址:http://www.blogjava.net/rosen/archive/2010/06/13/323522.html ...
- Java Web Service 学习
参考原文: http://blog.csdn.net/ostrichmyself/article/details/6393627 http://www.cnblogs.com/Jessy/p/3528 ...
- PG_RMAN备份遇到 domain socket
在用pg_rman做数据全备时:出现异常错误! [postgres@sdserver40_210 run]$ pg_rman backup --backup-mode=full --progress ...
- [BIM]案例
以下是中建三局BIM小组的项目,用以参考: BIM协同设计与质量控制 现实建筑物实体都是以三维空间状态存在,若用三维设计表达更具有优势.如复杂管综设计,一般情况下,二维AutoCAD设计是在建筑.结构 ...
- [OSG][转]osg格式文件
转自:http://blog.csdn.net/timothyfly/article/details/7826139 osg格式文件中如何处理多个节点共享一个子节点 下面一段程序中,共有三个Group ...
- C++的try_catch异常
http://blog.sina.com.cn/s/blog_a9303fd901018ost.html 大部分内容转自:http://blog.csdn.net/codestinity/articl ...
- 2016 ACM/ICPC Asia Regional Qingdao Online HDU5879
链接:http://acm.hdu.edu.cn/showproblem.php?pid=5879 解法:我们知道到某个极限之后结果相同,所以找到那个极限,其他保存之后输出就好了 #include&l ...
- [转]varchar(n),nvarchar(n) 长度、性能、及所占空间分析
varchar(n),nvarchar(n) 中的n怎么解释: nvarchar(n)最多能存n个字符,不区分中英文. varchar(n)最多能存n个字节,一个中文是两个字节. 所占空间: nvar ...
- webform数据导出
把数据放到一个泛型集合里,再把泛型集合里面的数据放到一个table中,设置好文件路径,然后进行文件读取,最后供用户下载. 数据导出放在一个按钮中就可以了 using System; using Sys ...
- gd-jpeg: JPEG library reports unrecoverable error 解决办法
Warning: imagecreatefromjpeg() [function.imagecreatefromjpeg]: gd-jpeg: JPEG library reports unrecov ...