SwiftUI 小组件 Widget(一)

概览


WidgetKit 将小组件放置在 iOS 主屏幕或 macOS 通知中心,让用户可以方便地访问你 App 中的相关内容。让你的小组件保持最新状态,以便用户始终可以一目了然地掌握最新信息。当他们需要更多详细信息时,你的小组件会直接将他们转至你 App 中的适当位置。

以上是苹果对小组件大概的介绍,简单的说就是小组件是用来展示你APP里面想让用户看到的东西,并且可以跳转到APP内的指定位置


这张是小组件的结构图,其中Configuration为小组件配置,分为动态配置IntentConfiguration, 跟静态配置StaticConfiguration (后面会细说这2个配置)

Provide则是负责小组件更新时间的一个对象,里面包括Snapshot (处理小组件缩影,如果小组件渲染需要时间,则这里可以处理渲染前的状态),Timeline entry(处理小组件更新策略)

View content 是渲染小组件的view

创建小组件

1、在 Xcode 中打开你的 App 项目,并选取“File” >“New” >“Target”

搜索Widget, 选择WidgetExtension,然后Next

我们先来创建不能编辑小组件,先将Include Configuration Intent 勾选去掉,然后写入小组件工程的名称,finish,这里会有个弹窗直接点Activity就行了

创建完之后就可以看到我们的目录下多了个文件夹,这里就是小组件文件存放的位置;会发现这里也有Assets,Info.plist 这2个文件,因为这里已经是个Target,相当于是另外一个APP,所以资源文件跟配置都独立起来

开发前了解

我们小组件创建好之后,我们在看一下每个文件里面是啥东西,更好方便我们开发

1、WidgetNotIntentBundle

@main

struct WidgetNotIntentBundle: WidgetBundle {

    var body: some Widget {

        WidgetNotIntent()

    }

}

WidgetBundle顾名思义是存放小组件的背包,body里面放的是需要展示的小组件,可以放多个,如下:

@main
struct WidgetNotIntentBundle: WidgetBundle {
    var body: some Widget {
        WidgetNotIntent()
        Widget1()
        Widget2()
        Widget3()
    }
}

2、WidgetNotIntent

接下来看重点文件(我这边取名叫WIdgetNotInten,具体看你们的命名)WIdgetNotIntent,这个文件里面的内容,其实就是我们刚开始提到的小组件结构,这次我们就不按结构顺序介绍了,按系统给我们生成的代码顺序介绍

Provider

Provider 继承 TimelineProvider,主要提供预览状态,以及时间线刷新策略,下面是Provide内的方法

a、placeholder(in context: Context) -> SimpleEntry

当 WidgetKit 首次显示你的小组件时,它会将小组件的视图呈现为一个占位符。占位符视图显示小组件的通用表示,让用户可以大致了解小组件显示的内容。

也就是我们数据没有加载出来前所展示给用户的状态

func placeholder(in context: Context) -> SimpleEntry {
    SimpleEntry(date: Date())
}

b、getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ())

要在小组件库中显示你的小组件,WidgetKit 会要求提供程序提供预览快照。context 参数的isPreview 属性来识别这一预览请求。当 isPreview 为 true 时,WidgetKit 会在小组件库中显示你的小组件。作为回应,你需要快速创建预览快照。如果小组件所需的资产或信息需要一些时间才能生成或从服务器获取,请改用示例数据。

这里的预览快照显示就是在第一步WidgetBundle添加小组件的那个页面

func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) {
        let entry: SimpleEntry
        if context.isPreview {
            entry = SimpleEntry(date: Date())
        } else {
            entry = SimpleEntry(date: Date())
        }
        
        completion(entry)
    }

c、getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ())

在请求初始快照后,WidgetKit 调用getTimeline以向提供程序请求定期时间线。时间线由一个或多个时间线条目以及一个重新载入策略构成,该策略用于告知 WidgetKit 何时请求后续时间线。

下面是系统提供的例子,创建5个时间线条目,每个小时会刷新一次小组件,且在最后一个时间线过期后会重新请求时间线。

func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
       var entries: [SimpleEntry] = []

       // Generate a timeline consisting of five entries an hour apart, starting from the current date.
       let currentDate = Date()
       for hourOffset in 0 ..< 5 {
           let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
           let entry = SimpleEntry(date: entryDate)
           entries.append(entry)
       }

       let timeline = Timeline(entries: entries, policy: .atEnd)
       completion(timeline)
  }

SimpleEntry

SimpleEntry为时间线条目,继承于TimelineEntry,为上述getTimeline方法中的Timeline提供时间参数,也可以新增其他参数,供Widget使用

struct SimpleEntry: TimelineEntry {
    let date: Date
}

WidgetNotIntentEntryView

这个EntryView是系统以我们的项目创建的一个默认小组件视图,默认显示这个View。我们可以在这里写我们小组件的UI布局,这里系统设置了个参数entry,Widget在调用这个View的时候把entry传进来。

struct WidgetNotIntentEntryView : View {
    
    var entry: Provider.Entry

    var body: some View {
        Text(entry.date, style: .time)
    }
}

WidgetNotIntentWidget

WIdget该小组件的入口,这里主要是对小组件的配置,包括尺寸的支持,小组件唯一标识,如果是支持动态配置的小组件还有个Intent属性(配置文件),显示的小组件名称,小组件说明等。

struct WidgetNotIntentWidget: Widget {
    let kind: String = "MyWidget"

    var body: some WidgetConfiguration {
        StaticConfiguration(kind: kind, provider: Provider()) { entry in
            WidgetNotIntentEntryView(entry: entry)
        }
        .supportedFamilies([.systemSmall, .systemMedium, .systemLarge])
        .configurationDisplayName("My Widget")
        .description("This is an example widget.")
    }
}

看着body里面的包含关系是不是很熟悉,是的,就是刚开始那Widget结构图的左边部分

WidgetNotIntentWidget_Previews

Preview这部分是实时显示你代码效果的,需要打开Canvas,打开方式如下;

可以根据调整family值,显示不同尺寸效果的预览图

struct WidgetNotIntentWidget_Previews: PreviewProvider {
    static var previews: some View {
        WidgetNotIntentEntryView(entry: SimpleEntry(date: Date()))
            .previewContext(WidgetPreviewContext(family: .systemSmall))
    }
}

OK,先带大家了解一下小组件,小组件创建,以及创建后各个文件内的意思。后续会继续介绍,尺寸,时间线刷新,可配置小组件(静态,动态),以及各个小组件实现的例子

  • 22
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值