这里每天分享一个 iOS 的新知识,快来关注我吧

前言

小组件系列传送门:

iOS 小组件开发第一篇:基础介绍
iOS 小组件开发第二篇:时间线
iOS 小组件开发第三篇:实战
iOS 小组件开发第四篇:小组件的尺寸
iOS 小组件开发第五篇:开发可配置的小组件
iOS 小组件开发第六篇:点击事件和交互
iOS 小组件开发第七篇:锁屏小组件
iOS 小组件开发第八篇:灵动岛开发
iOS 小组件开发第九篇:在 iOS 17 上创建可交互的小组件
iOS 小组件开发第十篇:小组件动画

当你的项目中已有小组件使用 Xcode 15 编译安装的时候,可能会看到一些不符合预期的情况,这是因为 Xcode 15 中更改了一些小组件的内部策略,以及提供了一些新的 API,今天来讲讲如何兼容这些情况。

containerBackground API

如果你的小组件有使用 background 来设置背景颜色,那么在添加小组件的时候可能会收到这个错误:

iOS 小组件开发第十二篇:iOS 17 适配

苹果提示需要适配 containerBackground API,这是 iOS 17 新出的一个用来填充 View 背景颜色的接口,因为今年开始苹果把小组件带到了整个苹果生态中,包括 macOS Sonoma,也包括锁屏的 StandBy 模式。

在一些特殊的场景下,苹果不希望开发者自己自定义背景颜色,比如 StandBy 模式,有背景颜色会看起来非常突兀,为了兼容这种情况,苹果才推出了这个新的 API。

要适配这个 API 也非常简单,只需要把 background 改成 containerBackground,但是 containerBackground 在 iOS 17 可用,如果你的小组件支持 iOS 17 以下,这里就会报错。所以可以通过给 View 增加一个扩展的方式来兼容:

extension View {
    func widgetBackground(_ backgroundView: some View) -> some View {
        // 如果是 iOS 17,则使用 containerBackground
        if #available(iOSApplicationExtension 17.0, *) {
            return containerBackground(for: .widget) {
                backgroundView
            }
        } else {
            return background(backgroundView)
        }
    }
}

在设置背景颜色的时候就可以直接使用这个新方法了:

struct MyWidgetEntryView : View {
    var entry: Provider.Entry
    var body: some View {
        VStack {
            Spacer()
            HStack {
                Spacer()
                Text(entry.date, style: .time)
                Spacer()
            }
            Spacer()
        }
        .widgetBackground(backgroundView: Color.red)
    }
}

再次运行程序,发现提示已经消失了。

边距问题

当你试图使用一个 View 将小组件完全填充时,可能会发现有一部分边距始终无法填充,类似下边这样:

iOS 小组件开发第十二篇:iOS 17 适配

这是因为在 iOS 17 中小组件默认把安全区域改成了一个默认的边距,可以使用新的 API contentMarginsDisabled 来禁用这个默认的边距,同样这个方法只支持 iOS 17,因此仍然需要写个扩展来兼容:

extension WidgetConfiguration {
    func disableContentMarginsIfNeeded() -> some WidgetConfiguration {
        if #available(iOSApplicationExtension 17.0, *) {
            return self.contentMarginsDisabled()
        } else {
            return self
        }
    }
}

注意这个方法是作用在 WidgetConfiguration 上的,所以使用的时候应该写在这里:

struct MyWidget: Widget {
    let kind: String = "MyWidget" // 唯一标识
    var body: some WidgetConfiguration {
        StaticConfiguration(kind: kind, provider: Provider()) { entry in
            MyWidgetEntryView(entry: entry)
        }
        .configurationDisplayName("这是小组件的名称")
        .description("这是小组件的描述.")
        .supportedFamilies([.systemSmall, .systemMedium, .systemLarge])
        .disableContentMarginsIfNeeded()
    }
}

再次运行程序,发现边距消失了,一切回归正常 。

iOS 小组件开发第十二篇:iOS 17 适配

这里每天分享一个 iOS 的新知识,快来关注我吧

本文同步自微信公众号 “iOS新知”,每天准时分享一个新知识,这里只是同步,想要及时学到就来关注我吧!