ios swiftui_使用SwiftUI引入iOS 14 WidgetKit
ios swiftui
WWDC 2020 gave us a lot of enhancements and updates, but the introduction of the WidgetKit framework unarguably stands out.
WWDC 2020给了我们很多增强和更新,但是WidgetKit框架的引入无疑是引人注目的。
iOS 14 has introduced a redesigned home screen, with the inclusion of widgets being a huge addition. Widgets are not just an eye-pleasing UI shortcut for our apps. They also aid in providing useful information to the user from time to time.
iOS 14引入了重新设计的主屏幕,其中包括小部件的增加。 小部件不仅是我们应用程序令人愉悦的UI快捷方式。 它们还有助于不时向用户提供有用的信息。
In some ways, they’re a calmer form of notification that provides you with the latest information from the apps (if the developer has opted to do so) without intruding. Additionally, there’s a new Smart Stack feature in iOS 14 that groups a set of widgets that you can swipe through. Smart Stacks tend to provide the relevant widget at the top by using on-device intelligence that takes into account the time of the day, location, and some other attributes.
在某些方面,它们是一种比较平静的通知形式,可为您提供应用程序的最新信息(如果开发人员选择这样做),而不会造成干扰。 此外,iOS 14中有一个新的智能堆栈功能,该功能将一组可滑动的小部件分组。 智能堆栈倾向于通过使用设备上的智能功能在顶部提供相关的小部件,该功能考虑了一天中的时间,位置和其他一些属性。
WidgetKit is built purely using SwiftUI, which opens endless opportunities for building beautiful widgets. It’s important to note than WidgetKit isn’t meant to build mini-apps.
WidgetKit完全是使用SwiftUI构建的,这为构建漂亮的窗口小部件提供了无限的机会。 值得注意的是,WidgetKit并非旨在构建迷你应用程序。
Besides providing a Link
button that lets you set a deep-link URL to navigate to a particular part of your application, you can’t add any animations or other interactions in widgets.
除了提供允许您设置深层链接URL的Link
按钮以导航到应用程序的特定部分外,您不能在小部件中添加任何动画或其他交互。
我们的目标 (Our Goal)
- Understanding the anatomy of WidgetKit. We’ll explore the framework and see how widgets are created and updated. 了解WidgetKit的结构。 我们将探索该框架,并了解如何创建和更新小部件。
- Build a Joke of the Hour widget in SwiftUI. 在SwiftUI中构建一个小时笑话小部件。
-
Bundle our SwiftUI application with two widgets by using
WidgetBuilder
.使用
WidgetBuilder
我们的SwiftUI应用程序与两个小部件捆绑WidgetBuilder
。
Without further ado, let’s get started.
事不宜迟,让我们开始吧。
WidgetKit框架:深入了解 (WidgetKit Framework: Under the Hood)
To understand the anatomy of WidgetKit, let’s create a new Xcode 12 SwiftUI project and ensure that the SwiftUI App Lifecycle is chosen.
为了了解WidgetKit的结构,让我们创建一个新的Xcode 12 SwiftUI项目,并确保选择了SwiftUI App Lifecycle。
To create our first widget, Go to File → New → Target and select the Widget Extension template. Make sure you uncheck “Include Configuration Intent,” as we’ll only cover static configurations in this article.
要创建我们的第一个窗口小部件,请转到文件→新建→目标,然后选择窗口小部件扩展模板。 确保取消选中“包括配置意图”,因为本文仅介绍静态配置。
Upon adding the Widget Extension Target, you’ll be greeted with a file containing a bunch of SwiftUI code that might seem new to you. Don’t worry, we’ll walk through all of it.
添加了Widget扩展目标后,您将得到一个包含一堆SwiftUI代码的文件,这对您来说似乎很新。 不用担心,我们将逐步介绍所有内容。
The following snippet is the starting point of your widget:
以下代码段是小部件的起点:
These are the inferences drawn from the code above:
这些是从上面的代码得出的推论:
-
kind
is an identifier used to distinguish the widget from others in the WidgetCenter.kind
是用于在WidgetCenter中将小部件与其他小部件区分开的标识符。 -
Inside
WidgetConfiguration
, we set a Placeholder view that’s displayed while the widget loads. The contents of the widget are set inside theFirstWidgetEntryView
that we’ll see shortly.在
WidgetConfiguration
内部,我们设置了占位符视图,该视图在小部件加载时显示。 小部件的内容在FirstWidgetEntryView
内部设置,我们将很快看到。 -
Provider
is a struct of typeTimelineProvider
that’s the core engine of the widget. It’s responsible for feeding the widget with data and setting intervals for updating the data. Again, we’ll come to this shortly.Provider
是TimelineProvider
类型的结构,它是小部件的核心引擎。 它负责为小部件提供数据并设置更新数据的时间间隔。 再次,我们很快会谈到这一点。 -
The view modifiers
configurationDisplayName
anddescription
display respective information in the Widget Gallery — a place that hosts all the widgets on your device.视图修饰符
configurationDisplayName
和description
在“小部件库”中显示各自的信息,该位置是设备上所有小部件的存放位置。
There’s another new modifier for the WidgetKit framework (supportedFamilies
) inside which we can pass the different sizes of widgets we want for our application. For example, .supportedFamilies([.systemLarge])
allows only large-sized widgets.
WidgetKit框架还有另一个新的修饰符( supportedFamilies
),在其中可以传递应用程序所需大小不同的小部件。 例如, .supportedFamilies([.systemLarge])
仅允许使用大尺寸的小部件。
WidgetKit时间线提供者 (WidgetKit Timeline Provider)
As the name suggests, the Provider
struct looks to provide data for the widget’s content. It conforms to a TimelineProvider
protocol that requires the implementation of two methods (snapshot
and timeline
), as shown in the default example given below:
顾名思义, Provider
结构将为小部件的内容提供数据。 它符合TimelineProvider
协议,该协议要求实现两种方法( snapshot
和timeline
),如下面给出的默认示例所示:
-
The
snapshot
function is used to immediately present a widget view, while the Timeline Provider looks to load the data. It’s important that you set the snapshot method with dummy data only, as this view would be displayed in Widget Gallery too.snapshot
功能用于立即显示窗口小部件视图,而时间轴提供程序则用于加载数据。 重要的是,仅将快照方法设置为仅包含伪数据,因为此视图也将显示在“小部件库”中。 -
The
SimpleEntry
struct is what actually holds the data for a singleTimelineEntry
and is eventually displayed in the widget’s content.SimpleEntry
结构实际上是保存单个TimelineEntry
数据的结构,并最终显示在小部件的内容中。 -
The
timeline
function, on the other hand, is used to create one or more entries. We can set the time interval after which theTimelineEntry
needs to be updated.另一方面,
timeline
功能用于创建一个或多个条目。 我们可以设置时间间隔,之后需要更新TimelineEntry
。 - The code above basically adds five timeline entries that would be used to update the widget’s content hourly. The data set in the default example is the date text. 上面的代码基本上添加了五个时间轴条目,这些条目将用于每小时更新一次小部件的内容。 默认示例中设置的数据是日期文本。
-
The
Timeline
instance also contains aTimelineReloadPolicy
. The system would use this policy to determine when to invoke thetimeline
function again — for loading the next set of timeline entries. In the code above, the policy is set asatEnd
, which means after the fifthSimpleEntry
is displayed on the widget, the system would trigger thetimeline
function for the next batch.Timeline
实例还包含一个TimelineReloadPolicy
。 系统将使用此策略来确定何时再次调用timeline
功能-用于加载下一组时间轴条目。 在上面的代码中,该策略设置为atEnd
,这意味着在小部件上显示第五个SimpleEntry
之后,系统将触发下一批的timeline
功能。 -
Besides
atEnd
, we also have aafter(Date:)
property. It is used to set a specific date at which we want the next timeline to be fetched. Do note that system may not fire thetimeline
function at the exact date. Also, we can set anever
as the reload policy to ensure the timeline is not fired again.除了
atEnd
,我们还有一个after(Date:)
属性。 它用于设置一个特定的日期,在该日期我们要获取下一个时间轴。 请注意,系统可能不会在确切的日期触发timeline
功能。 另外,我们可以设置一个never
作为重载策略,以确保不会再次触发时间轴。
Additionally, if you want to trigger a reload of widget entries, you can use the WidgetCenter
API. It lets us reload a particular timeline or all timelines.
此外,如果要触发窗口小部件条目的重新加载,则可以使用WidgetCenter
API。 它使我们可以重新加载特定时间轴或所有时间轴。
The TimelineProvider
struct is incredibly important, as your dynamic content would be fetched in it to update the widget’s content on specific intervals of your choice.
TimelineProvider
结构非常重要,因为将在其中提取动态内容,以便在您选择的特定时间间隔内更新小部件的内容。
SwiftUI小部件视图 (SwiftUI Widget View)
Now that we’re clear on how WidgetKit operates under the hood, let’s look at the SwiftUI view that’ll display the widget on the screen.
现在我们已经了解了WidgetKit如何在后台运行,让我们看一下将在屏幕上显示小部件的SwiftUI视图。
The struct above populates the widget’s view with the data set in the Provider.Entry
. Provider.Entry
is the data source for our widget’s view, and if you look back at the TimelineProvider
, you’ll see SimpleEntry
struct was set as the type alias for Entry
.
上面的结构使用Provider.Entry
设置的数据填充小部件的视图。 Provider.Entry
是小部件视图的数据源,如果您回头看一下TimelineProvider
,您会看到SimpleEntry
结构被设置为Entry
的类型别名。
Now that we’ve seen how WidgetKit operates — from displaying Placeholder to populating the widget views with Timeline entries specified in the TimelineProvider
— we’re ready to build our own custom widget: a jokes tracker that updates every hour (you can customize the time interval).
现在我们已经了解了WidgetKit的工作方式-从显示占位符到使用TimelineProvider中指定的TimelineProvider
线条目填充小部件视图-我们已经准备好构建自己的自定义小部件:一个每小时更新一次的笑话跟踪器(您可以自定义时间间隔)。
在iOS 14中构建笑话小部件跟踪器 (Build a Jokes Widget Tracker in iOS 14)
The TimelineProvider
lets us fetch data from network requests or a database while the PlaceholderView
is displayed. The approach to fetching data from an API for widgets is the same as you’d do for the application.
当显示PlaceholderView
, TimelineProvider
允许我们从网络请求或数据库中获取数据。 从小部件的API提取数据的方法与您对应用程序的处理方法相同。
The following code uses a Combine-powered URLSession
to decode the API response and pass it through a completion block:
以下代码使用具有组合功能的URLSession
解码API响应并将其传递给完成块:
Do note that SwiftUI widget views cannot and should not be updated using property wrappers like Published
or State
.
请注意,SwiftUI小部件视图不能并且不应使用诸如Published
或State
类的属性包装程序进行更新。
The response is decoded using the following Codable struct:
使用以下Codable结构解码响应:
创建我们的数据源 (Creating Our Data Source)
Our widget would display the jokes as a string. So, let's add the field in our SimpleEntry
struct as shown below:
我们的小部件会将笑话显示为字符串。 因此,让我们将字段添加到我们的SimpleEntry
结构中,如下所示:
struct JokesEntry: TimelineEntry {public let date: Date
public let joke : String}
创建时间轴提供者 (Creating a Timeline Provider)
The following timeline provider structure fetches the data from DataFetcher
and sets them on an array of TimelineEntries
configured at a given time interval:
以下时间轴提供程序结构从DataFetcher
获取数据,并将其设置在以给定时间间隔配置的TimelineEntries
数组上:
Note: Setting a time interval of seconds isn’t recommended in production applications. The code snippet above does that for demonstration purposes only.
注意:在生产应用程序中,不建议将时间间隔设置为秒。 上面的代码段仅用于演示目的。
创建小部件SwiftUI视图 (Creating Widget SwiftUI View)
The following piece of code represents our SwiftUI view with the SimpleEntry
struct set as its data source:
以下代码段代表我们的SwiftUI视图,其中将SimpleEntry
结构设置为其数据源:
In the code above, by using the SwiftUI @ViewBuilder
and using the widgetFamily
enum type as an EnvironmentObject, we’ve set different SwiftUI views for various widget shapes.
在上面的代码中,通过使用SwiftUI @ViewBuilder
并将widgetFamily
枚举类型用作EnvironmentObject,我们为各种控件形状设置了不同的SwiftUI视图。
Finally, let’s set our WidgetConfiguration
and launch the application on an iOS 14 device:
最后,让我们设置WidgetConfiguration
并在iOS 14设备上启动应用程序:
Here is the output of the widget in action:
这是运行中的小部件的输出:
As you can see, we have two widgets of different sizes and different layouts. You can further customize them with your own beautiful SwiftUI views.
如您所见,我们有两个不同大小和布局的小部件。 您可以使用自己美丽的SwiftUI视图进一步自定义它们。
For demonstration purposes, I’ve set the TimelineProvider
interval to one second (though it isn’t ideal in widgets and can eat a lot of battery).
出于演示目的,我将TimelineProvider
间隔设置为一秒(尽管它在小部件中并不理想,并且会消耗大量电池)。
使用小部件生成器创建多个小部件 (Using Widget Builder for Creating Multiple Widgets)
We can create different widgets and bundle them together using a WidgetBundleBuilder
:
我们可以创建不同的小部件,并使用WidgetBundleBuilder
它们捆绑在一起:
结论 (Conclusion)
Widgets are handy and pleasing to the eyes. As Apple has introduced a new WidgetKit framework and widgets on the home screen on iOS, a lot of applications will look to leverage it. However, it’ll be interesting to see how much of an impact it has on user privacy. The full source code is available in the GitHub repository.
小部件方便且令人愉悦。 随着Apple在iOS的主屏幕上引入了新的WidgetKit框架和小部件,许多应用程序都希望利用它。 但是,有趣的是,它对用户隐私产生了多大影响。 完整的源代码可在GitHub存储库中找到 。
In the next part, we’ll use intent configurations and links to build some handy widgets.
在下一部分中,我们将使用意图配置和链接来构建一些方便的小部件。
That’s it for this one. Thanks for reading.
就这个。 谢谢阅读。
翻译自: https://medium.com/better-programming/introducing-ios-14-widgetkit-with-swiftui-a9cc473caa24
ios swiftui