iOS配置App小组件(Widget)的行为和外观
iOS配置App小组件(Widget)的行为和外观

iOS配置App小组件(Widget)的行为和外观

在Widget中,可以通过配置WidgetConfiguration来修改App小组件的行为和行为。

例如,当想要在App小组件的列表视图中显示标题和描述时,可以在Widget中设置configurationDisplayName和description进行配置,同时可以设置supportedFamilies实现固定组件尺寸的支持。

struct BankletWidget: Widget {
    @State private var background: String = "bg0"
    let kind: String = "BankletWidget"
    
    var body: some WidgetConfiguration {
        StaticConfiguration(kind: kind, provider: SimpleProvider()) { entry in
            BankletWidgetEntryView(entry: entry)
                .containerBackground(for: .widget) {
                    Image("WidgetBackground")
                }
        }
        .supportedFamilies([.systemSmall]) // 支持小尺寸
        .configurationDisplayName("进度小组件") // 小组件的显示名称
        .description("显示当前存钱罐的进度百分比.") // 小组件的描述
    }
}

WidgetConfiguration修饰符

在 WidgetConfiguration 中,除了 .configurationDisplayName 和 .description 之外,还有其他一些常用的修饰符可以用于配置小组件的行为和外观。以下是一些常见的修饰符及其作用:

1、.supportedFamilies

用于指定小组件支持的家庭(尺寸)。

小组件家庭包括:.systemSmall、.systemMedium、.systemLarge 和 .systemExtraLarge(仅适用于 iPad)。

示例:

.supportedFamilies([.systemSmall, .systemMedium, .systemLarge])

2、.contentMarginsDisabled

用于禁用小组件的默认内容边距。

如果设置为 true,小组件的内容将延伸到边缘。

示例:

.contentMarginsDisabled()

3、.widgetURL

用于为小组件设置一个深链接(URL)。

当用户点击小组件时,会打开指定的 URL。

示例:

.widgetURL(URL(string: "Banklet://widget"))

需要注意的是,widgetURL 是用于为整个小组件设置一个深链接(Deep Link)的。每个小组件只能有一个 widgetURL,它会覆盖小组件中其他视图的 widgetURL。因此,无论点击小组件的哪个部分,都会触发同一个 widgetURL。

StaticConfiguration(kind: kind, provider: SimpleProvider()) { entry in
        BankletWidgetEntryView(entry: entry)
            .containerBackground(for: .widget) {
                Image("WidgetBackground")
            }
            .widgetURL(URL(string: "Banklet://Percentage")) // 第一个
            .widgetURL(URL(string: "Banklet://TestLink"))  // 第二个
    }
.supportedFamilies([.systemSmall]) // 支持小尺寸

由于 widgetURL 是覆盖式的,只有最后一个 widgetURL 会生效,所以无论点击小组件的哪个部分,都会触发 Banklet://TestLink。

如果想要实现通过点击小组件的不同区域触发不同的链接,可以使用Link实现:

Link(destination: URL(string: "Banklet://LoopAnimation")!) {
    Image("LoopAnimation") // 显示存钱罐图标
        .resizable()
        .scaledToFit()
        .imageScale(.large)
}

Link 组件会自动处理打开 URL 的操作。

4、.widgetAccentable

用于设置小组件是否支持强调色(Accent Color)。

如果设置为 true,小组件会使用系统的强调色。

示例:

Text("MON") // 这行文本会被放入强调组
    .font(.caption)
    .widgetAccentable(true) // 将此文本及其子视图添加到强调组
    .foregroundColor(.accentColor) // 设置强调色
    
Text("6") // 这行文本不在强调组中
    .font(.title)
    .widgetAccentable(true) // 将此文本及其子视图添加到强调组

widgetAccentable 只有在小组件使用 accented 渲染模式时才会生效。确保小组件在 accented 模式下进行渲染,否则不会看到任何颜色变化。

在某些情况下,需要在小组件的 widgetFamily 设置中明确声明强调颜色。通过修改系统的强调色(accentColor)来影响小组件的渲染。

设置 accentColor 来明确指定强调颜色。

var body: some View {
    VStack {
        Text("MON")
            .font(.caption)
            .widgetAccentable() // 强调渲染
            .foregroundColor(.accentColor) // 设置强调色
        Text("6")
            .font(.title)
    }
    .accentColor(.red) // 设置强调颜色为红色
}

5、.widgetLabel

widgetLabel 主要用于 Accessory Family Widgets,这些小组件用于表盘上的配件部分(例如 Apple Watch 的表盘角落、圆形小组件等)。它提供了一种在特定区域显示文本标签的方式,通常用于描述小组件或提供一些额外的上下文信息。      

假设正在创建一个在 Apple Watch 表盘上显示天气的小组件,可以使用 widgetLabel 来描述当前的天气状态:

var body: some View {
    VStack {
        Text("22°C")
            .font(.title)
            .widgetLabel("Current temperature")  // 用于在表盘上显示的附加文本标签
    }
}

在这个例子中,widgetLabel 会在表盘的小组件区域显示 “Current temperature” 文本,用于描述小组件所展示的内容。

提示

不适用于所有小组件:widgetLabel 只在 accessoryCorner 和 accessoryCircular 类型的小组件中有效。如果使用的是常规的小组件(如 systemSmall, systemMedium 等),它可能不会显示或产生预期效果。

不会直接显示在主视图中:widgetLabel 提供的标签不会直接在主视图上显示,它的作用是供系统在合适的情况下使用。例如,在配件小组件区域显示文本。

6、onBackgroundURLSessionEvents

该方法允许小组件在后台接收和处理与 URLSession 相关的事件。通常,这在需要后台更新、从网络请求数据等场景中使用。例如,当小组件需要获取最新数据或进行网络请求时,可以使用这个方法来处理这些请求。

使用场景

后台刷新:当小组件需要从网络获取数据时,即使它不处于前台,也可以在后台继续处理这些任务。

处理后台请求:例如,如果小组件展示的是天气信息、股票数据等,这些信息会定期从网络请求,因此需要在后台处理这些网络事件。

参数

matching:可以是一个匹配的字符串,或者是一个闭包,用于决定是否匹配某个 URLSession 事件。

urlSessionEvent:触发事件时执行的闭包,用来处理 URLSession 事件。

.onBackgroundURLSessionEvents(matching: "com.example.weatherData") { identifier, completion in
    // 处理天气数据的后台事件
    fetchWeatherData { success in
        // 完成请求后调用 completion 回调
        completion()
    }
}

在这个例子中,使用了一个匹配字符串 ” com.example.weatherData ” 来识别特定的 URLSession 事件。当小组件在后台接收到这个事件时,触发 fetchWeatherData 方法,完成数据获取后调用 completion(),标记事件完成。

如何实现 fetchWeatherData:

func fetchWeatherData() {
    // 创建 URLSession 配置
    let config = URLSessionConfiguration.background(withIdentifier: "com.example.weatherData")
    let session = URLSession(configuration: config)

    let url = URL(string: "https://api.weather.com/data")!
    let task = session.dataTask(with: url) { data, response, error in
        // 处理请求返回的天气数据
    }
    task.resume()
}

注意

onBackgroundURLSessionEvents 仅在 iOS 17 及以上版本有效,并且适用于具有后台任务的 Widget,例如新闻或天气应用等。

小组件必须具备支持后台处理的能力,可能需要在 Info.plist 中进行相应配置,以便允许后台刷新。

7、disfavoredLocations

该方法允许指定某些位置不适合显示特定的小组件。举例来说,可能不希望某个小组件显示在锁屏上,或者某个小组件只适用于某些尺寸的 Widget(如 .systemSmall、.systemMedium 等)。

使用场景

不推荐某些小组件显示在特定位置:例如,某些 Widget 可能不适合在锁屏上显示,或者在某些小尺寸的 Widget 中可能无法良好显示。

优化小组件体验:通过避免小组件在不适合的位置显示,可以提升用户体验,使其更加符合设计需求。

参数

locations:是一个数组,包含 WidgetLocation 枚举值,表示不希望小组件显示的具体位置。例如,.lockScreen、.homeScreen 等。

families:指定该配置适用的 Widget 尺寸,通常是一个 WidgetFamily 数组。

示例代码

// 在小组件的配置中使用 disfavoredLocations 禁止某些位置显示
.disfavoredLocations([.lockScreen], for: [.systemSmall, .systemMedium])

这个示例中,我们禁止小组件显示在锁屏上(.lockScreen),并且适用于 .systemSmall 和 .systemMedium 两种 Widget 尺寸。

可用位置和尺寸

位置(WidgetLocation):如 .lockScreen(锁屏)、.homeScreen(主屏幕)等。

尺寸(WidgetFamily):如 .systemSmall、.systemMedium、.systemLarge、.accessoryCorner 等。

disfavoredLocations 的作用是指定某些小组件位置或区域不允许显示某些特定类型的小组件。然而,这并不完全意味着这些小组件会从所有位置中消失,尤其是对于锁屏上的小组件。它只是会避免在某些特定位置(例如锁屏)显示该小组件。

disfavoredLocations 只是在系统的 WidgetKit 配置中表示该小组件不推荐显示在某些位置(如锁屏)。但是,用户仍然可以选择是否将小组件放置在锁屏或其他位置。因此,这个方法的作用并不强制性,它更多的是一种建议,指示系统最好不要在特定位置显示该小组件。

disfavoredLocations 主要是给系统的一个提示,告诉系统在哪些位置不希望显示该小组件。

用户仍然可以手动将小组件添加到锁屏位置,所以即使设置了 .lockScreen,如果用户选择,依然会看到小组件。

如果希望完全禁止某个位置显示小组件,用户的操作也可能绕过这个设置,除非在系统层面(例如通过配置限制)强制性禁止。

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开放者。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注