关于ios:iOS-14Widget开发

2次阅读

共计 3316 个字符,预计需要花费 9 分钟才能阅读完成。

Widget 相似一个迷你版的 App,能够快速访问 App 提供的信息—比方天气、事件、笔记等。Widget 还能够充当“快捷方式”,点击它会立刻跳转到 App 的指定地位。

介绍

  • WidgetKit 通过在 iOS 主屏幕或 macOS 告诉核心搁置小部件,让用户能够随时拜访 App 中的内容。Widget 能够放弃更新,从而让用户取得最新信息。当须要查看 App 的更多细节时,Widget 会间接跳转到 App 中的适当地位。
  • Widget 有三种不同的尺寸(小号、中号和大号),能够对 Widget 进行个性化定制。
  • 要实现一个 Widget,须要给利用增加一个 Widget 扩大并只能应用 SwiftUI 来实现 Widget 的内容。

App 实现

Widget 寄宿于 App,所以首先必须将 App 性能实现。

增加 Widget

  1. 点击我的项目,抉择File > New > Target
  2. Application Extension 中,抉择Widget Extension,而后点击Next
  3. 输出扩展名的名称。
  4. 单击Finish
  5. 此时会生成一个新文件夹,蕴含以下内容

    • 扩展名.swift
    • 扩展名.intentdefinition
    • Assets.xcassets
    • Info.plist

数据共享

App 与 Widget 能够通过 网络数据和本地数据 两种形式进行数据的共享。

  • 网络数据可通过 URLSession 实现数据的申请与解析。
  • 本地数据共享能够通过 App Groups,它是 iOS 8 之后推出的在 App 之间共享数据的形式,只须要简略的配置就能够实现数据的共享。(本文以此为例)

配置

  1. App 在 Signing&Capabilities 中关上App Groups,内容个别为group.Bundle Identifier
  2. Widget 必须在 Signing&Capabilities 中关上App Groups,内容与 App 保持一致。

如果文件须要共享,能够选中 App 中须要共享给 Widget 的文件,而后勾选 Widget 的 Target。

实现

配置实现当前,能够通过 UserDefaultsFileManager来实现 App 与 Widget 的数据共享,这里以 UserDefaults 为例,因为 SwiftUI 提供了 @AppStorage 来简化操作。

  • App
`// 蕴含 App Groups 的 UserDefaults
@AppStorage("contact", store: UserDefaults(suiteName: "group.cn.abc.yf.SwiftUI-Widget"))

// 而后在前面保留数据 ` 复制代码
  • Widget
`@AppStorage("contact", store: UserDefaults(suiteName: "group.cn.abc.yf.SwiftUI-Widget"))

// 而后在前面取出数据 ` 复制代码

编写 Widget

  1. 原理:开发者通过 SwiftUI 构建 Views,定义 Timelines 为 Views 提供对应工夫所需的数据,当数据变动时,通过 reload 更新数据。TimelineProvider提供一组 TimelineEntryReloadPolicy,用来后续刷新页面。
  2. 实现 Widget 的代码绝对比拟模版,能够从 Widget 的入口开始,缺什么补什么。563513413,不论你是大牛还是小白都欢送入驻

入口

`@main
struct UserWidget: Widget {
    private let kind: String = "UserWidget"

    public var body: some WidgetConfiguration {}}` 复制代码
  • kind:字符串,惟一标识 Widget。
  • WidgetConfiguration:有两类配置,别离为

    • StaticConfiguration : 能够在不须要用户任何输出的状况下自行解析,能够在 Widget 的 App 中获取相干数据并发送给 Widget。
    • IntentConfiguration:依赖于 App 的 Siri Intent,会主动接管这些 Intent 并用于更新 Widget,用于构建动静 Widget。
  • .supportedFamilies:反对不同尺寸。

内容

不论是哪种配置,都须要提供以下内容。

Entry

渲染 Widget 所需的 数据模型 ,须要恪守TimelineEntry 协定。

`struct Model: TimelineEntry {
    let date: Date
    // 显示的内容 Model
}` 复制代码

Provider

恪守 TimelineProvider 协定,通知 WidgetKit 何时渲染与刷新 Widget。须要实现以下 3 个办法:

`struct Provider: TimelineProvider {
    // 占位视图,是一个规范的 SwiftUI View,当第一次展现或者产生谬误时都会展现该 View。func placeholder(in context: Context) -> TimelineEntry { }

    // 编辑屏幕在左上角抉择增加 Widget、第一次展现时会调用该办法
    func getSnapshot(in context: Context, completion: @escaping (TimelineEntry) -> Void) { }

    // 进行数据的预处理,转化成 Entry
    // 最初肯定要调用 completion,进而刷新 Widget
    func getTimeline(in context: Context, completion: @escaping (Timeline<TimelineEntry>) -> Void) {}}` 复制代码
  1. getTimeline 是最重要的办法,前面的数据刷新都会在其中实现,所以可能会在其中实现最新的网络数据和本地数据的获取,而后转成 Model 以供应用。
  2. getTimeline 的办法里有一个 policy 参数,示意刷新的机会,能够抉择.never(不刷新),.atEnd(Entry 显示结束之后主动刷新)或 .after(date)(达到某个特定工夫后主动刷新)
  3. Widget 刷新的工夫由零碎对立决定(有时候设置了也不会本人刷新),如果须要强制刷新 Widget,能够在 App 中应用 WidgetCenter 来从新加载所有工夫线:WidgetCenter.shared.reloadAllTimelines()

EntryView

屏幕上 Widget 显示的内容,能够针对不同尺寸的 Widget 设置不同的 View。

`struct EntryView: View {

    var entry: Provider.Entry // 数据模型

    @Environment(.widgetFamily) var family // 尺寸环境变量

    @ViewBuilder
    var body: some View {
        switch family {
        case .systemSmall:
            // 小尺寸
        case .systemMedium:
            // 中尺寸
        default:
            // 大尺寸
        }
    }
}` 复制代码
  1. Widget 能且只能应用 SwiftUI 构建界面。
  2. Widget 实质:一个随着工夫线而更新的 SwiftUI View。

运行

  • 先运行 App
  • 再运行 Widget

交互

只能点击,点击会关上 App。也能够通过 .widgetURL(myDeeplink) 办法配置当 Widget 被点击时触发哪个 Deep Linking,也能够通过应用链接使 Widget 的不同局部触发不同的 Deep Linking(能够间接了解为 Widget 只是一个按钮,点按这个按钮会跳转到指定 URL 对应的页面)。

  • Widget 点击
`// 某个 Widget 内容
var body: some View {
    VStack {Link(destination: homeDeepLink) {Text("主页")
        }
        Link(destination: settingsDeepLink) {Text("设置")
        }
    }.widgetURL(myDeeplink)
}` 复制代码
  • App 解决
`@main
struct SwiftUIApp: App {
    var body: some Scene {
        WindowGroup {ContentView()
                .onOpenURL(perform: { url in
                    print(url)
                })
        }
    }
}` 复制代码

源代码

正文完
 0