详解iOS14 Widget 开发相关及易报错地方处理
首先了解下如何创建
Xcode -> File -> New -> Target 找到 Widget Extension
如果你的 Widget 支持用户配置属性,则需要勾选这个(例如天气组件,用户可以选择城市),不支持的话则不用勾选
了解下创建Widget后,系统给我们生成的文件内容
下面这个代码是没有勾选 Include Configuration Intent 的地方
Provider
// Provider,顾名思义为小组件提供信息得一个struct struct Provider: TimelineProvider { public typealias Entry = SimpleEntry // 编辑屏幕时,左上角选择添加小组件时候,第一次展示小组件会走这个方法 public func snapshot(with context: Context, completion: @escaping (SimpleEntry) -> ()) { } // 这个方法内可以进行网络请求,拿到的数据保存在对应的 entry 中,调用 completion 之后会到刷新小组件 public func timeline(with context: Context, completion: @escaping (Timeline<Entry>) -> ()) { // 例如这是一个网络请求 Network.request { data in let entry = SimpleEntry(date: renderDate, data: data) let timeline = Timeline(entries: [entry], policy: .after(nextRequestDate)) completion(timeline) } } }
Entry
官方解释: A type that specifies the date to display a widget, and, optionally, indicates the current relevance of the widget's content.
// 我的理解是就是存储小组件的数据的一个东西 struct SimpleEntry: TimelineEntry { let date: Date let data: Data }
PlacehodlerView
// 这个是一个默认视图,例如网络请求失败、发生未知错误、第一次展示小组件都会展示这个view struct PlaceholderView : View { }
WidgetEntryView
// 这个是我们需要布局小组件长什么样子的view struct StaticWidgetEntryView : View { }
主入口
@main struct StaticWidget: Widget { private let kind: String = "StaticWidget" public var body: some WidgetConfiguration { StaticConfiguration(kind: kind, provider: Provider(), placeholder: PlaceholderView()) { entry in StaticWidgetEntryView(entry: entry) } .configurationDisplayName("My Widget") .description("This is an example widget.") } }
支持多Widget样式
@main struct MainWidgets: WidgetBundle { @WidgetBundleBuilder var body: some Widget { Widget1() Widget2() } }
勾选 Include Configuration Intent 之后可能出错的地方
如果你的app中设置了 Class Prefix 这下面这个 ConfigurationIntent.self 则需要加上对应的前缀
例如前缀是 XY 则需要修改为 XYConfigurationIntent.self
@main struct MainWidget: Widget { private let kind: String = "MainWidget" public var body: some WidgetConfiguration { IntentConfiguration(kind: kind, intent: XYConfigurationIntent.self, provider: Provider(), placeholder: PlaceholderView()) { entry in IntentWidgetEntryView(entry: entry) } .configurationDisplayName("My Widget") .description("This is an example widget.") } }
处理Widget点击事件
Widget 支持三种显示方式,分别是 systemSmall 、 systemMedium 、 systemLarge
small 样式只能用 widgetUrl 处理
@ViewBuilder var body: some View { ZStack { AvatarView(entry.character) .widgetURL(url) .foregroundColor(.white) } .background(Color.gameBackground) }
medium 和 large 可以用 Link 或者 widgetUrl 处理,我们看到里面有四个相同的view,即左边图片,右边文字的,这个view代码如下(Link方式)
struct RecipeView: View { let recipe: RecipeModel var body: some View { Link(destination: URL(string: "你的网址")!) { HStack { WebImageView(imageUrl: recipe.squareImageUrl) .frame(width: 65, height: 65) Text(recipe.adjName + recipe.name) .font(.footnote) .bold() .foregroundColor(.black) .lineLimit(3) } } } }
添加 Link 或 widgetUrl 后,点击每个 RecipeView 都会触发事件,这时候你需要在主项目中的 AppDelegate 中的如下方法进行处理
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { }
关于Widget中加载网络图片的时机
当我们在func timeline(withcompletion)这个方法中请求到数据拿到图片链接后,必须同步把图片解析出来,否则直接让对应的WidgetView去load url 是加载不出来的
正确的写法
Struct Model { ... let image: UIImage } func timeline(with context: Context, completion: @escaping (Timeline<LFPlanEntry>) -> ()) { Network.request { data in // 解析图片 var image: UIImage? = nil if let imageData = try? Data(contentsOf: url) { image = UIImage(data: imageData) } let model = Model(image: image ?? defalutImage) // 这里给个默认图片 let entry = SimpleEntry(date: entryDate, data: model) let timeline = Timeline(entries: [entry], policy: .atEnd) completion(timeline) } } Struct WidgetView: View { let model: Model @ViewBuilder var body: some View { Image(uiImage: model.image) .resizable() } }
错误的写法(直接丢url给view去加载)
struct WidgetView : View { let model: Model @State private var remoteImage : UIImage? = nil let defaultImage = UIImage(named: "default")! var body: some View { Image(uiImage: self.remoteImage ?? defaultImage) .onAppear(perform: fetchRemoteImage) } func fetchRemoteImage() { guard let url = URL(string: model.url) else { return } URLSession.shared.dataTask(with: url){ (data, response, error) in if let image = UIImage(data: data!){ self.remoteImage = image } else { print(error ?? "") } }.resume() } }
基于我们的app做出来的简单效果图
Widget相关资料
Widgets
Creating a Widget Extension
Keeping a Widget Up To Date
Making a Configurable Widget
到此这篇关于详解iOS14 Widget 开发相关及易报错地方处理的文章就介绍到这了,更多相关iOS14 Widget开发内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!
相关文章
- 这篇文章主要介绍了浅谈关于如何检测iOS14本地网络权限的一些思路,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-12-08
苹果ios14照片怎么添加说明? 苹果ios14照片说明的用法
苹果ios14照片怎么添加说明?苹果ios14系统新增了照片说明,想要给图片添加说明,该怎么操作呢?下面我们就来看看苹果ios14照片说明的用法,需要的朋友可以参考下...2020-12-08- 这篇文章主要介绍了PyQt5 实现给无边框widget窗口添加背景图片的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-09
- 这篇文章主要介绍了详解iOS14 Widget 开发相关及易报错地方处理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-10-12
ios14照片小组件不显示照片怎么办? ios14精选照片的添加方法
ios14照片小组件不显示照片怎么办?ios14添加了照片小组件,却发现不显示照片,该怎么解决呢?下面我们就来看看ios14精选照片的添加方法,需要的朋友可以参考下...2020-12-08- CWidget是所有Widget的基类。CWidget是自包含组件,可以看出是MVC的简略版,CWidget相比Controller,既没有actions,也没有filters widget,英文意思为小工具,小挂件,在程序...2016-11-25
- 这篇文章主要介绍了Flutter项目在 iOS14 启动崩溃的解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-09-24
- 这篇文章主要介绍了Android开发之AppWidget详解,想了解桌面程序AppWidget的同学可以参考下...2021-04-10
- 这篇文章主要介绍了thinkPHP下的widget扩展用法,结合实例形式分析widget扩展的具体使用技巧与注意事项,需要的朋友可以参考下...2015-12-28
- 这篇文章主要介绍了WordPress中使主题支持widget以及添加插件启用函数的方法,使WP可以使用小工具widget与通过register_activation_hook()来添加启用插件的函数,需要的朋友可以参考下...2015-12-24
- 这篇文章主要介绍了PyQt5 QDockWidget控件应用详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-08-12
- 这篇文章主要介绍了Yii中创建自己的Widget实现方法,结合具体实例形式较为详细的分析了Yii中创建Widget的步骤与实现技巧,需要的朋友可以参考下...2016-01-07
- 这篇文章主要介绍了CI框架整合widget(页面格局)的方法,分析了widget页面格局的作用及CI框架整合widget的具体实现方法,需要的朋友可以参考下...2016-05-20
- 这篇文章主要介绍了Android小部件Widget开发过程中的坑和问题小结,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-10-01
- 这篇文章主要介绍了PyQt 如何创建自定义QWidget,帮助大家更好的理解和学习使用pyqt,感兴趣的朋友可以了解下...2021-03-20
PyQt5 QTreeWidget 树形结构递归遍历当前所有节点的实现
Qt中实现树形结构可以使用QTreeWidget类,也可以使用QTreeView类,本文主要介绍了PyQt5QTreeWidget树形结构递归遍历当前所有节点的实现,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-11-28- TabWidget组件配合自定义Dialog组件,可实现一个复杂的多窗体分页结构。这篇文章就主要介绍了如何通过TabWidget实现多窗体的创建,感兴趣的小伙伴可以了解一下...2021-12-03
- 本文主要介绍了TreeWidget的如何使用,实现对树形框多节点的各种操作,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-11-28