美文网首页
Widget 学习 Keeping a Widget Up to

Widget 学习 Keeping a Widget Up to

作者: 弑神指 | 来源:发表于2020-11-05 10:20 被阅读0次

    Keeping a Widget Up To Date (使小部件保持最新)

    计划小部件的时间轴,以使用动态视图及时显示相关信息,并在发生变化时更新时间轴。

    总览

    小部件使用SwiftUI视图显示其内容。WidgetKit在一个单独的过程中代表您呈现视图。结果,即使窗口小部件在屏幕上,窗口小部件扩展也不会持续处于活动状态。尽管您的窗口小部件并非总是处于活动状态,但是有几种方法可以使它的内容保持最新。

    生成可预测事件的时间表

    许多小部件具有可预测的时间点,在这些时间点更新其内容是有意义的。
    例如,
    1.显示天气信息的小部件可能会在一整天内每小时更新一次温度。
    2.股市窗口小部件可以在公开市场时间频繁更新其内容,但周末则不能完全更新。
    通过提前计划这些时间,WidgetKit会在适当的时间到来时自动刷新您的窗口小部件。

    在定义小部件时,实现一个定制的TimelineProvider。
    WidgetKit从提供程序获取时间轴,并使用它来跟踪何时更新小部件。
    时间轴是TimelineEntry对象的数组。时间轴中的每个条目都有日期和时间,以及小部件显示其视图所需的其他信息。
    除了时间线条目之外,时间线还指定了一个刷新策略,告诉WidgetKit何时请求新的时间线。

    以下是显示角色健康状况的游戏小部件的示例。
    当健康水平低于100%时,角色的恢复速度为每小时25%。
    例如,当角色的健康等级为25%时,需要3个小时才能完全恢复到100%。
    下图显示了WidgetKit如何从提供程序请求时间轴,并在时间轴条目中指定的每个时间渲染窗口小部件。

    WidgetKit-Timeline-At-End@2x.png

    当WidgetKit最初请求时间轴时,提供程序创建一个包含四个条目的时间轴。
    第一个条目表示当前时间,后面是每小时的三个条目。
    由于刷新策略设置为默认的atEnd, WidgetKit在时间轴条目中的最后日期之后请求一个新的时间轴。
    当时间轴中的每个日期到达时,WidgetKit将调用小部件的内容闭包并显示结果。
    最后一个时间线条目通过后,WidgetKit通过向提供者请求新的时间线重复该过程。
    因为角色的运行状况已经达到100%,提供者会响应一个当前时间的单一条目,并将刷新策略设置为never。通过这个设置,WidgetKit不会要求另一个时间轴,直到应用程序使用WidgetCenter告诉WidgetKit请求一个新的时间轴。

    除了atEnd和never refresh策略之外,如果时间线在到达条目末尾之前或之后可能发生更改,提供程序还可以完全指定不同的日期。
    例如,如果一条龙将在2小时内出现,向角色挑战战斗,提供程序将重载策略设置为after(_:),将日期在2小时后传递。
    下图显示了WidgetKit在呈现小部件2小时后如何请求一个新部件。

    WidgetKit-Timeline-After-Date@2x.png

    由于与龙的战斗,角色的治疗将需要额外2小时达到100%。新的时间轴包含两个条目,一个是当前时间,另一个是未来2小时。时间轴为刷新策略指定atEnd,表示没有其他已知事件可能改变时间轴。

    当两个小时过去,并且角色的健康达到100%时,WidgetKit询问提供者一个新的时间表。
    因为角色的健康状况已经恢复,提供者生成与上面第一个图表相同的最终时间线。
    当用户玩游戏时,角色的健康水平发生变化时,应用程序会使用WidgetCenter让WidgetKit刷新时间轴并更新小部件。

    除了指定时间线结束之前的日期外,提供程序还可以指定时间线结束之后的日期。
    当您知道小部件的状态直到稍后才会改变时,这是非常有用的。
    例如,股票市场小部件可以在周五市场收盘时创建时间轴,使用afterDate()刷新策略指定周一市场开盘时间。因为股市在周末关闭,所以在股市开盘前没有必要更新widget。

    时间线更改时通知WidgetKit

    您的应用程序可以告诉WidgetKit,当有事情影响到widget的当前时间轴时,请求一个新的时间轴。
    在上面的游戏小部件的例子中,如果应用程序收到一个推送通知,表明一个队友给了角色一剂治疗药水,应用程序可以告诉WidgetKit重新加载时间轴并更新小部件的内容。
    要重新加载特定类型的小部件,你的应用程序使用WidgetCenter,如下所示:

    WidgetCenter.shared.reloadTimelines(ofKind: "com.mygame.character-detail")
    

    kind参数包含与用于创建小部件的WidgetConfiguration值相同的字符串。

    如果小部件具有用户可配置的属性,请使用WidgetCenter来验证是否存在具有适当设置的小部件,从而避免不必要的重新加载。
    例如,当游戏收到一个关于一个角色收到治疗药水的推送通知时,它会在重新加载时间线之前验证一个小部件是否显示了这个角色。

    在下面的代码中,应用程序调用getCurrentConfigurations(_:)来检索用户配置的小部件列表。
    然后迭代得到的WidgetInfo对象,找到一个意图与接受治疗药水的角色配置的对象。
    如果找到一个,应用程序就会调用reloadTimelines(ofKind:)来描述该小部件的类型。

    WidgetCenter.shared.getCurrentConfigurations { result in
        guard case .success(let widgets) = result else { return }
    
        // Iterate over the WidgetInfo elements to find one that matches
        // the character from the push notification.
        if let widget = widgets.first(
            where: { widget in
                let intent = widget.configuration as? SelectCharacterIntent
                return intent?.character == characterThatReceivedHealingPotion
            }
        ) {
            WidgetCenter.shared.reloadTimelines(ofKind: widget.kind)
        }
    }
    

    如果你的应用程序使用WidgetBundle来支持多个小部件,你可以使用WidgetCenter来重新加载所有小部件的时间线。
    例如,如果你的小部件需要用户登录到一个帐户,但他们已经注销,你可以通过调用重新加载所有小部件:

    WidgetCenter.shared.reloadAllTimelines()
    

    显示动态日期

    由于您的窗口小部件扩展程序并非始终运行,因此您无法直接更新窗口小部件的内容。
    而是,WidgetKit代表您渲染窗口小部件的视图并显示结果。
    但是,某些SwiftUI视图可让您显示在可见窗口小部件时继续更新的内容。

    使用Text小部件中的视图,您可以在屏幕上显示最新的日期和时间。以下示例显示了可用的组合。

    要显示自动更新的相对时间:

    let components = DateComponents(minute: 11, second: 14)
    let futureDate = Calendar.current.date(byAdding: components, to: Date())!
    
    Text(futureDate, style: .relative)
    // Displays:
    // 11 min, 14 sec
    
    Text(futureDate, style: .offset)
    // Displays:
    // -11 minutes
    

    使用相对样式显示当前日期和时间与指定日期之间的绝对差异,而不管该日期是将来的还是过去的。
    偏移样式显示当前日期和时间与指定日期之间的差异,表示未来的日期使用减号(-)前缀,表示过去的日期使用加号(+)前缀。

    要显示继续自动更新的计时器:

    let components = DateComponents(minute: 15)
    let futureDate = Calendar.current.date(byAdding: components, to: Date())!
    
    Text(futureDate, style: .timer)
    // Displays:
    // 15:00
    

    对于将来的日期,timer样式将递减计数,直到当前时间达到指定的日期和时间为止,并在日期经过时递增计数。

    要显示绝对日期或时间:

    // Absolute Date or Time
    let components = DateComponents(year: 2020, month: 4, day: 1, hour: 9, minute: 41)
    let aprilFirstDate = Calendar.current(components)!
    
    Text(aprilFirstDate, style: .date)
    Text("Date: \(aprilFirstDate, style: .date)")
    Text("Time: \(aprilFirstDate, style: .time)")
    
    // Displays:
    // April 1, 2020
    // Date: April 1, 2020
    // Time: 9:41AM
    

    最后,显示两个日期之间的时间间隔:

    let startComponents = DateComponents(hour: 9, minute: 30)
    let startDate = Calendar.current.date(from: startComponents)!
    
    let endComponents = DateComponents(hour: 14, minute: 45)
    let endDate = Calendar.current.date(from: endComponents)!
    
    Text(startDate ... endDate)
    Text("The meeting will take place: \(startDate ... endDate)")
    
    // Displays:
    // 9:30AM-2:45PM
    // The meeting will take place: 9:30AM-2:45PM
    

    后台网络请求完成后更新

    当您的小部件扩展处于活动状态时,比如在提供快照或时间轴时,它可以发起后台网络请求。
    这个过程类似于应用程序处理这种类型的请求,这在后台下载文件中有描述。
    WidgetKit不是恢复你的应用程序,而是直接激活widget的扩展。
    要处理网络请求的结果,使用onBackgroundURLSessionEvents(matching:_:)修饰符到你的小部件的配置,并执行以下操作:

    • 存储对completion参数的引用。您在处理所有网络事件后调用完成处理程序。
    • 使用identifier参数查找URLSession启动后台请求时使用的对象。
      如果您的窗口小部件扩展名已终止,请使用标识符重新创建URLSession。

    在调用onBackgroundURLSessionEvents()后,系统调用您提供给urlSession的URLSessionDelegate的urlSession(_:downloadTask:didFinishDownloadingTo:)方法。
    当所有的事件都被传递后,系统调用委托的urlSessionDidFinishEvents(forBackgroundURLSession:)方法。

    要在网络请求完成后刷新小部件的时间轴,请从您的委托的urlSessionDidFinishEvents实现中调用WidgetCenter方法。
    完成事件处理后,调用之前存储在onBackgroundURLSessionEvents()中的完成处理程序。

    另外阅读

    时间线管理

    protocol TimelineProvider

    建议WidgetKit何时更新窗口小部件显示的类型。

    protocol IntentTimelinProvider

    建议WidgetKit何时更新用户可配置的窗口小部件显示的类型。

    struct TimelineProviderContext

    一个对象,其中包含有关如何渲染小部件的详细信息,包括其大小以及它是否出现在小部件库中。

    protocol TimelineEntry

    一种类型,指定显示窗口小部件的日期,并可选地指示窗口小部件内容的当前相关性。

    struct Timeline

    一个对象,指定WidgetKit更新窗口小部件视图的日期。

    class WidgetCenter

    包含用户配置的小部件列表的对象,用于重新加载小部件时间线。

    相关文章

      网友评论

          本文标题:Widget 学习 Keeping a Widget Up to

          本文链接:https://www.haomeiwen.com/subject/jvlovktx.html