详解iOS14 Widget 开发相关及易报错地方处理

2025-05-29 0 89

首先了解下如何创建

xcode -> file -> new -> target 找到 widget extension

详解iOS14 Widget 开发相关及易报错地方处理

如果你的 widget 支持用户配置属性,则需要勾选这个(例如天气组件,用户可以选择城市),不支持的话则不用勾选

了解下创建widget后,系统给我们生成的文件内容

下面这个代码是没有勾选 include configuration intent 的地方

provider

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19
// 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.

?

1

2

3

4

5
// 我的理解是就是存储小组件的数据的一个东西

struct simpleentry: timelineentry {

let date: date

let data: data

}

placehodlerview

?

1

2

3

4
// 这个是一个默认视图,例如网络请求失败、发生未知错误、第一次展示小组件都会展示这个view

struct placeholderview : view {

}

widgetentryview

?

1

2

3

4
// 这个是我们需要布局小组件长什么样子的view

struct staticwidgetentryview : view {

}

主入口

?

1

2

3

4

5

6

7

8

9

10

11

12
@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样式

?

1

2

3

4

5

6

7

8

9

10
@main

struct mainwidgets: widgetbundle {

@widgetbundlebuilder

var body: some widget {

widget1()

widget2()

}

}

勾选 include configuration intent 之后可能出错的地方

如果你的app中设置了 class prefix 这下面这个 configurationintent.self 则需要加上对应的前缀

例如前缀是 xy 则需要修改为 xyconfigurationintent.self

?

1

2

3

4

5

6

7

8

9

10

11

12
@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 处理

?

1

2

3

4

5

6

7

8

9
@viewbuilder

var body: some view {

zstack {

avatarview(entry.character)

.widgeturl(url)

.foregroundcolor(.white)

}

.background(color.gamebackground)

}

medium 和 large 可以用 link 或者 widgeturl 处理,我们看到里面有四个相同的view,即左边图片,右边文字的,这个view代码如下(link方式)

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18
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 中的如下方法进行处理

?

1

2

3
func application(_ app: uiapplication, open url: url, options: [uiapplication.openurloptionskey : any] = [:]) -> bool {

}

关于widget中加载网络图片的时机

当我们在func timeline(withcompletion)这个方法中请求到数据拿到图片链接后,必须同步把图片解析出来,否则直接让对应的widgetview去load url 是加载不出来的

正确的写法

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30
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去加载)

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24
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做出来的简单效果图

详解iOS14 Widget 开发相关及易报错地方处理

widget相关资料

widgets

creating a widget extension

keeping a widget up to date

making a configurable widget

到此这篇关于详解ios14 widget 开发相关及易报错地方处理的文章就介绍到这了,更多相关ios14 widget开发内容请搜索快网idc以前的文章或继续浏览下面的相关文章希望大家以后多多支持快网idc!

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 详解iOS14 Widget 开发相关及易报错地方处理 https://www.kuaiidc.com/89194.html

相关文章

发表评论
暂无评论