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/ ...
随机推荐
- ALTFP_CONVERT IP使用与仿真
ALTFP_CONVERT IP使用与仿真 近期项目要使用到整型数据转浮点型数据,将16位的整数转换为单精度浮点数(32bit).本打算自己写逻辑实现的,不过考虑到本身项目时间紧,能力也有限,就没 ...
- HDU 2236:无题II(二分搜索+二分匹配)
http://acm.hdu.edu.cn/showproblem.php?pid=2236 题意:中文题意. 思路:先找出最大和最小值,然后二分差值,对于每一个差值从下界开始枚举判断能不能二分匹配. ...
- js instanceof运算符
a instanceof B; instanceof检测对象a的原型链中有没有构造函数B.prototype 如下: function In (a, B) { var p = a.__proto__; ...
- python-day 1
学python--脚本语言 为了更好的以后,为了更好的自己,加油!!! 1.安装虚拟机如果遇到这样的错误:此主机支持intel vt-x 处于禁用状态错误 解决方法: 进入BIOS后,找到“Syste ...
- preparedStatement和Statement 有什么不一样
1. PreparedStatement接口继承Statement, PreparedStatement 实例包含已编译的 SQL 语句,所以其执行速度要快于 Statement 对象. 2.作 ...
- LA 4064 Magnetic Train Tracks
题意:给定平面上$n(3\leq n \leq 1200)$个无三点共线的点,问这些点组成了多少个锐角三角形. 分析:显然任意三点可构成三角形,而锐角三角形不如直角或钝角三角形容易计数,因为后者有且仅 ...
- Robberies(简单的01背包 HDU2955)
Robberies Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Sub ...
- Safecracker 分类: HDU 搜索 2015-06-25 21:12 12人阅读 评论(0) 收藏
Safecracker Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total S ...
- python学习笔记-day4笔记 常用内置函数与装饰器
1.常用的python函数 abs 求绝对值 all 判断迭代器中所有的数据是否为真或者可迭代数据为空,返回真,否则返回假 any ...
- camera isp
1. 目标手机摄像头模组用ISP功能模块的市场走向及研发方向.为能够正确认识手机摄像模组行业提供技术及市场依据.2. ISP在模组上的应用原理2.1 功能区域无论数码相机.摄像机或者摄像手机,其影像数 ...