这篇文章主要介绍了详解iOS14 Widget 开发相关及易报错地方处理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
首先了解下如何创建
Xcode -> File -> New -> Target 找到 Widget Extension
// 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 Widget 开发相关及易报错地方处理
- 详解flutter engine 那些没被释放的东西 2022-12-04
- Android MaterialButton使用实例详解(告别shape、selector) 2023-06-16
- 作为iOS开发,这道面试题你能答出来,说明你基础很OK! 2023-09-14
- Android实现轮询的三种方式 2023-02-17
- Android实现监听音量的变化 2023-03-30
- Android studio实现动态背景页面 2023-05-23
- SurfaceView播放视频发送弹幕并实现滚动歌词 2023-01-02
- 最好用的ios数据恢复软件:PhoneRescue for Mac 2023-09-14
- Flutter实现底部和顶部导航栏 2022-08-31
- iOS 对当前webView进行截屏的方法 2023-03-01
